CopyFile function only works on xp - file

I have a delphi form with a button on it. At the click of this button, it allows user to browse for a file and copy the file to a directory.
My code for the function is this:
function TdmData.CopyAFile(Const Sourcefile, DestFile: string): boolean;
var Src, Dest : PChar;
begin
Src := StrAlloc(Length(SourceFile)+1);
Dest := StrAlloc(Length(DestFile)+1);
try
StrPCopy(Src,SourceFile);
StrPCopy(Dest,DestFile);
result := (CopyFile(Src,Dest,FALSE));
finally
StrDispose(Src);
StrDispose(Dest);
end;
end;
The click event for the button:
CopyAFile(fn, Path +'\'+ ExtractFileName(fn));
What I cant understand when I run this form and press the button on a win XP machine, it works fine, if I browse to the directory to where it is being copied to I can see the file in there.
However running this form on a later OS such as Win 8.1 it does not copy the file, again checking the directory I see no file in there.
I don't get any errors, I've stepped through the code which goes through fine.
Has anyone ever come across this or have an idea what the cause could be? If so any help would be great.

You are not doing any error checking.
If the CopyFile function fails, the return value is zero. To get extended error information call GetLastError (or raise an exception via RaiseLastOSError)
e.g.
if not CopyFile(A, B, False) then
RaiseLastOSError;
or equivalently
Win32Check(CopyFile(A, B, False));
BTW, correct usage is:
CopyFile(PChar(Sourcefile) , PChar(Destfile), False);
No need for the extra allocations.
If you do not include a UAC manifest, then your application is running in virtualized mode. And saving files to restricted areas e.g. Program Files will not raise any errors but actually save the file into a virtual store location e.g. [CSIDL_LOCAL_APPDATA]\VirtualStore\Program Files.

Related

DBF File with unreadable fields. Are they encrypted, encoded weird, or something else?

I have a program that installs an updated database monthly into a special software we use. I get an .exe, run it, the .exe "installs" a bunch of DBF/CDX files into a folder, and then "hooks up" the database info into our software somehow.
Here is what the "installation" output folder looks like every month:
I've opened the DBF I'm most interested pulling info from (parts.dbf) (with at least 4 different pieces of software I believe) and browsed the data. Most of the fields look fine, readable, all is good. However, the 2 fields that I NEED (Prices and Part Numbers) are unreadable. In the Parts column all of the fields show 10 or 12 characters followed by a bunch of 9's (examples:<\MFMIFJHMFll999999999999999999, KI9e^Z]pbk^999999999999999999, JIFIPKMFL999999999999999999999). In the Price column its similar, just not as many characters (examples: LJKLGIQ999, IGII999999, JMQJGLL999).
Here is a screenshot of what I'm seeing exactly:
I have googled just about everything I know to google. I've downloaded different programs, tried to pull the data into Crystal Reports, tried to encode it differently (not sure I did that right, though), tried to figure out how to decrypt it (that journey was short-lived because it was so over my head), and just generally been pulling my hair out over this for weeks. I don't know what to do because I don't even really know where to begin. I'm just stabbing in the dark.
I THINK this file was created in some version of FoxPro but I could be wrong. When I view the information in our software it all shows up fine. Part Numbers and Prices look like readable human characters.
Example of data in our software:
I'm out of ideas. I need to know what I'm working with so I can work on figuring out how to "fix it". Is this a FoxPro file? Is it encoded in a way that I need to change? Is it encrypted data in those two fields? Am I way off on everything?
Ideally, I'd love to pull this data into Crystal Reports and do my reporting thing with the data. Even Excel could probably work okay. As it stands though I can't do much reporting with a bunch of weird characters and 9's.
Any help with this would be greatly appreciated.
Screenshot of Schema, per comment section:
Yes, 0x03 in header's first byte it is a Foxbase table. As cHao already pointed out, the author decided to create those columns with some byte shifting of each character (I wouldn't call that encryption though, too easy to solve for any programmer - or non-programmer with some pattern discovery).
Now the question is how you can utilize that data without damaging the original. One idea is to take a copy, alter the data in it and use that copy instead. Doing that with some computer language is easy when you are a programmer, but you are saying you are not. Then comes the question, which language code you could simply get and compile on your computer.
Well I wanted to play with this as a skill testing for myself and came up with some C# code. It was quite easy to write, and compile on any windows machine (so I thought, I had been doing that since years ago). I was mistaken, I don't know why nor have a will to investigate, but the executable created using command line compiler (any windows have it already) is blocked by my antivirus! I signed it but nothing changed. I gave up very quickly.
Luckily there was another choice which I think is better anyways. Go < g > write and compile with Go - the fantastic language from Google. If you want to spare your 10-15 mins at most to it, I will give you the code and how to compile it into an exe on your computer. First here is the code itself:
package main
import (
"fmt"
"log"
"path/filepath"
"strings"
"os"
"io"
"time"
"github.com/jmoiron/sqlx"
_ "github.com/mattn/go-adodb"
)
func main() {
if len(os.Args) != 2 {
log.Fatal("You need to supply an input filename.")
}
source := os.Args[1]
if _, err := os.Stat(source); os.IsNotExist(err) {
log.Fatal(fmt.Sprintf("File [%s] doesn't exist.", source))
}
log.Println(fmt.Sprintf("Converting [%s]...", source))
saveAs := GetSaveAsName(source)
log.Println(fmt.Sprintf("Started conversion on copy [%s]", saveAs))
ConvertData(saveAs)
log.Println("Conversion complete.")
}
func ConvertData(filename string) {
srcBytes := make([]byte, 127-32-1)
dstBytes := make([]byte, 127-32-1)
for i := 32; i < 34;i++ {
srcBytes[i-32]=byte(i+25)
dstBytes[i-32]=byte(i)
}
for i := 35; i < 127; i++ {
srcBytes[i-33] = byte(i+25)
dstBytes[i-33] = byte(i)
}
src := string(srcBytes) + string(byte('"')+25)
dst := string(dstBytes)
dbPath, dbName := filepath.Split(filename)
db, err := sqlx.Open("adodb", `Provider=VFPOLEDB;Data Source=` + dbPath)
e(err)
defer db.Close()
stmt := fmt.Sprintf(`update ('%s') set
p_part_num = chrtran(p_part_num, "%s", "%s"+'"'),
p_price = chrtran(p_price, "%s", "%s"+'"')`,
dbName, src, dst, src, dst)
_, err = db.Exec(stmt)
e(err)
}
func GetSaveAsName(source string) string {
fp, err := filepath.Abs(source)
e(err)
dir, fn := filepath.Split(fp)
targetFileName := filepath.Join(dir,
fmt.Sprintf("%s_copy%d.dbf",
strings.Replace(strings.ToLower(fn), ".dbf", "", 1),
time.Now().Unix()))
e(err)
in, err := os.Open(source)
e(err)
defer in.Close()
out, err := os.Create(targetFileName)
e(err)
defer out.Close()
_, err = io.Copy(out, in)
e(err)
err = out.Close()
e(err)
return targetFileName
}
func e(err error) {
if err != nil {
log.Fatal(err)
}
}
And here are the steps to create an executable out of it (and have Go as a language on your computer for other needs:)
Download Go language from Google and install it. Its installer is simple to use and finish in a few seconds.
Open a command prompt. Type:
Go version [enter]
-You should see installed Go's version (as of now 1.10).
-Type
Go env [enter]
and check GOPATH , it points the base folder for your go projects. Go to that folder and create 4 folders named:
bin, pkg, src and vendor
By default GOPATH is "Go" under your home folder, looks like this:
c:\users\myUserName\Go
after creating folders you would have:
c:\users\myUserName\Go
c:\users\myUserName\Go\bin
c:\users\myUserName\Go\pkg
c:\users\myUserName\Go\src
c:\users\myUserName\Go\vendor
using any text editor (Notepad.exe for example) copy & paste and save the code as say "MyCustomConverter.go" into src folder.
Code has 2 external libraries that you need to get. Change directory to your GOPATH (not really necessary but my habit at least) and get those libraries typing:
cd %GOPATH%
go get -v github.com/jmoiron/sqlx
go get -v github.com/mattn/go-adodb
You are ready to compile your code.
cd src
set GOARCH=386
go build MyCustomConverter.go
This would create MyCustomConverter.exe that you can use for conversion.
set GOARCH=386 is needed in this special case, because VFP OLEDB driver is 32 bits driver.
Oh I forgot to tell, it uses VFPOLEDB driver, which you can download from here and install.
You would use the executable like this:
MyCustomConverter.exe "c:\My Folder\parts.dbf"
and it would create a modified version of that named as:
"c:\My Folder\parts_copyXXXXXXXXXX.dbf"
where XXXXXXXXXXX would be a timestamp value (so whenever you run you create another copy, it doesn't overwrite on to one that may exist).
Instead of going to command prompt everytime and typing the fullpath of your parts table, you could copy the MyCustomConverter.exe file on to desktop and drag & drop your parts.dbf on to that exe from windows explorer.
(It was a nice exercise for my Go coding - there would be critics such as why I didn't use parameters but I really had good reasons, driver and the Go library support namely:)
I THINK this file was created in some version of FoxPro
While the DBF Data Tables were CREATED by Foxpro, they are POPULATED by an APPLICATION which may or may not have been written in Foxpro.
And yes, you do not need to worry about the CDX files unless you want to organize (sequence) the data by one of its Indexes or to establish Relationships between multiple Data Tables for processing purposes. However unless you were to do that using Foxpro/Visual Foxpro itself, it wouldn't be of use to you anyway.
From the comments that you have already received, it looks as though the developers of the APPLICATION that writes the field values into the DBF Data Tables might have encrypted the data. And it also seems like you may have found how to decrypt it using the suggestions above.
I'm no programmer unfortunately
If that is the case then I'd suggest that you STOP RIGHT NOW before you introduce more problems than you want. Blindly 'mucking' around with the data might just make things worse.
If this project is BUSINESS CRITICAL then you should hire a software consultant familiar with Foxpro/Visual Foxpro to get the work done - after which you can do whatever you want. Remember that if something is BUSINESS CRITICAL then it is worth spending the $$$$
Good Luck

SHCreateItemFromParsingName return FILE_NOT_FOUND when filename specified

I try get IShellItem for a file to copy it with IFileOperation COM interface from system directory to another directory. I must use exactly IFileOperation COM interface for this purpose.
When I specify full filename - return value from SHCreateItemFromParsingName() was ERROR_FILE_NOT_FOUND, but file present in the directory. When I delete filename from path below and use only folder path - all seems good, return value is S_OK.
//...
CoInitialize(NULL);
//...
WCHAR szSourceDll[MAX_PATH * 2];
wcscpy_s(szSourceDll, MAX_PATH, L"C:\\Windows\\System32\\sysprep\\cryptbase.dll");
r = CoCreateInstance(&CLSID_FileOperation, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_HANDLER, &IID_IFileOperation, &FileOperation1);
if (r != S_OK) return;
FileOperation1->lpVtbl->SetOperationFlags(FileOperation1, FOF_NOCONFIRMATION | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION);
r = SHCreateItemFromParsingName(szSourceDll, NULL, &IID_IShellItem, &isrc);
//...
CoUninitialize();
//...
Why this code, written in C, not working with filenames. How can I create IShellItem instance for file in system folder to copy it?
P.S.
Windows 7 x64, C, Visual Studio 2015, v140 platform toolset, additional dependencies: Msi.lib;Wuguid.lib;ole32.lib;ntdll.lib
P.P.S
It's properly work with files in user`s directories...
Assuming your application is compiled as a 32-bit application and running on a 64-bit OS, a file not found error is probably correct because your application is redirected to the 32-bit system directory (%WinDir%\SysWoW64).
In most cases, whenever a 32-bit application attempts to access %windir%\System32, %windir%\lastgood\system32, or %windir%\regedit.exe, the access is redirected to an architecture-specific path.
For more information, see File System Redirector on MSDN.
You could temporarily turn off redirection in your thread but it is not really safe to do this when calling shell functions, only functions in kernel32. If the API you are calling internally uses LoadLibrary and/or COM then the API might fail because it will be unable to load from system32 while redirection is disabled.
You can also access the native system32 directory with the %WinDir%\SysNative backdoor. This only works in 32-bit applications on 64-bit Vista+ so you must do some version detection.

AssignFile(): File access denied

I want to create a .txt file and write to it at any moment at run-time. To do this, I'm using the AssignFile() function. But I am having trouble in instances where my file already exists. I get an error that says: File access denied.
To better explain, see these two examples:
Ex1: if I call AssignFile() the first time when the file does not exist, OK! But, if the file exists, this does not work.
Ex2: if I call AssignFile() the second time (when AssignFile() was successful the first time), this also does not work.
Is this a bug in the AssignFile() function?
var
myfile: TextFile;
Procedure WriteFileContent(const MyTxtFile: string; MyNumber: DWORD);
var
F: TextFile;
Begin
If FileExists(MyTxtFile) Then
Begin
AssignFile(F, MyTxtFile);
Rewrite(F);
Writeln(F, '0x' + IntToHex(MyNumber,8));
CloseFile(F);
End;
End;
begin
try
// Calling AssignFile() by first time
AssignFile(myfile, 'myfile.txt');
Rewrite(myfile);
CloseFile(myfile);
setfileattributes('myfile.txt', FILE_ATTRIBUTE_HIDDEN);
Sleep(5000);
// Calling AssignFile() by second time
WriteFileContent('myfile.txt', 123456789);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
It is not AssignFile() that fails, but your call to Rewrite() on a file with the Hidden attribute set. Following explains it:
Typically you call Rewrite(F) in order to erase the file and write new data to it with subsequent Write(F, ...) or WriteLn(F, ...) calls.
From docs (System.Rewrite):
If an external file with the same name already exists, it is deleted
and a new empty file is created in its place.
There is no problem opening the file for writing with the Append() command.
(Based on above I drew the conclusion that it is the deletion that fails with the Access denied message. That was cutting the corners too much.)
Beaten by comments I traced through the code and compared actual code with MSDN documentation for CreateFile:
Actual code:
// if mode is fmOutput (as it is for Rewrite)
OpenMode = GENERIC_WRITE
Flags = CREATE_ALWAYS
// ...
Temp := CreateFile(t.Name, OpenMode, FILE_SHARE_READ, nil, Flags, FILE_ATTRIBUTE_NORMAL, 0);
And documentation:
If CREATE_ALWAYS and FILE_ATTRIBUTE_NORMAL are specified, CreateFile
fails and sets the last error to ERROR_ACCESS_DENIED if the file
exists and has the FILE_ATTRIBUTE_HIDDEN or FILE_ATTRIBUTE_SYSTEM
attribute.
Calling Rewrite() on a existing file with the hidden attribute fails always.

MING files running error

I am trying to run ADNI .mnc image in MATLAB
I added folder emma-master, niak-0.7.1-ammo, mia and niak-0.7.1-ammo to my path. All these folders are located in
D:\EMINA BURCH\PhD Thesis\MATLAB Packages
But when I want to open ._bq_t_15T.mnc located also in D:\EMINA BURCH\PhD Thesis\MATLAB Packages
that is h = openimage('._bq_n_15T.mnc')
I get the following error
Error using miinquire (line 145)
Error getting image dimensions from file D:\EMINA BURCH\PhD Thesis\MATLAB Packages._bq_n_15T.mnc
Error in openimage (line 173)
DimSizes = miinquire (filename, 'imagesize');
When I enter debug mode in minquire function after the line
[stat,out] = system(['mincinfo -vardims image ' minc_file]);
I get stat = 1 and out = 'mincinfo' is not recognized as an internal or external command, operable program or batch file.
May You, please help me with this issue.
system isn't able to automatically recognise the different requirements that might be needed to run the same system command on different operating systems. Using commands like ispc, isunix, ismac and computer, you can automatically check and call different versions of the commands as appropriate:
if ispc
[stat,out] = system(['mincinfo.exe -vardims image ' minc_file]);
else
[stat,out] = system(['mincinfo -vardims image ' minc_file]);
end
Of course, you also have to have the appropriate program on your MATLAB path for this to work.

Check file version of and .exe file (Server Side) and if newer download

I want to point to a http://somesite.com/somefile.exe and check the file version of the exe server side and compare the version info to the same .exe file all ready on my computer. If the server side file is newer then I want to down load it.
I have functions to download the file and check the file version but I want to check if the file version is newer than the one i have on my computer.
I do not want to download the exe to my computer and then check the file version.
Has anyone here been able to do this?
function GetVersion(sFileName:string): string;
var
VerInfoSize: DWORD;
VerInfo: Pointer;
VerValueSize: DWORD;
VerValue: PVSFixedFileInfo;
Dummy: DWORD;
begin
VerInfoSize := GetFileVersionInfoSize(PChar(sFileName), Dummy);
GetMem(VerInfo, VerInfoSize);
GetFileVersionInfo(PChar(sFileName), 0, VerInfoSize, VerInfo);
VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
with VerValue^ do
begin
Result := IntToStr(dwFileVersionMS shr 16);
Result := Result + '.' + IntToStr(dwFileVersionMS and $FFFF);
Result := Result + '.' + IntToStr(dwFileVersionLS shr 16);
Result := Result + '.' + IntToStr(dwFileVersionLS and $FFFF);
end;
FreeMem(VerInfo, VerInfoSize);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Http: TIdHTTP;
MS: TMemoryStream;
begin
Http := TIdHTTP.Create(nil);
try
MS := TMemoryStream.Create;
try
Http.OnWork:= HttpWork;
Http.Get('http://live.sysinternals.com/ADExplorer.exe', MS);
MS.SaveToFile('C:\ADExplorer.exe');
finally
MS.Free;
end;
finally
Http.Free;
end;
end;
You cannot access the file version remotely. You need to either download the file locally first, or you need to store the file version in a separate file that you can download, or you need to write a server-side script that your client can send a request to and have it access the file version and return it back to your client.
A better option is to use HTTP's built-in "Conditional GET" feature instead (if the server supports it). Your client can include an "If-Modified-Since" header in its request, then the server will deliver the requested file only if it has been modified on the server-side after the requested timestamp. Otherwise a 304 reply code will be sent back indicating the client already has the latest file. Read RFC 2616 Section 14.25 for more details.
You can't check the FileVersion of the file without physically having it to inspect, which means you have to be able to have all the bytes available, and the file version API functions expect a physical disk file. (IOW, you can't do this without downloading the file to your local drive first.)
Besides, you're already fully downloading it to memory with the HTTP GET anyway, so you're not saving anything in bandwidth in the first place.
The alternative (if it's an option) is to have a file on the server that contains the version number that the local file can download and read instead. If you can't do that, you're probably out of luck and will have to do the full download.

Resources