Reputation: 169
I invoked Kernel32's copy file method like that:
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFile(
[MarshalAs(UnmanagedType.LPStr)] string lpExistingFileName,
[MarshalAs(UnmanagedType.LPStr)] string lpNewFileName,
[MarshalAs(UnmanagedType.Bool)] bool bFailIfExists);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
However when I call it it return 2 from the GetLastError() which means file not found. The path certainly exists.
string newfile = Environment.CurrentDirectory + "\\temp" + Path.GetExtension(file);
uint i;
if (!CopyFile(file, newfile, true)) i = GetLastError();
I'm trying to bypass the LongPath exception with this solution. But it doesn't seem to work even with normal files. Any help would be appreciated.
Here's the complete code of Form1:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Shell32;
using System.Xml;
using System.Diagnostics;
using word = Microsoft.Office.Interop.Word;
using System.Runtime.InteropServices;
namespace DocumentCrawler
{
public partial class Form1 : Form
{
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFile(
[MarshalAs(UnmanagedType.LPStr)] string lpExistingFileName,
[MarshalAs(UnmanagedType.LPStr)] string lpNewFileName,
[MarshalAs(UnmanagedType.Bool)] bool bFailIfExists);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
public Form1()
{
InitializeComponent();
}
private void btnSearch_Click(object sender, EventArgs e)
{
progressBar.Style = ProgressBarStyle.Marquee;
lbProgress.Text = "Finding Word Documents";
btnSearch.Enabled = false;
lvResults.Clear();
SearchDirectory(tbDirectory.Text, tbField.Text);
btnSearch.Enabled = true;
}
void SearchDirectory(string path, string searchPattern)
{
List<string> docs = new List<string>();
foreach (string d in Directory.GetDirectories(path))
{
SearchDirectory(path + "\\" + d.Remove(0, d.LastIndexOf('\\') + 1), searchPattern);
}
foreach (string f in Directory.GetFiles(path))
{
if (Path.GetExtension(f) == ".docx" || Path.GetExtension(f) == ".doc")
{
docs.Add(f);
}
}
progressBar.Value = 0;
lbProgress.Text = "Processing Word Documents 0%";
progressBar.Maximum = docs.Count;
progressBar.Style = ProgressBarStyle.Blocks;
foreach (string f in docs)
{
string txt = TextFromDocument(f);
if (txt.Contains(searchPattern))
{
lvResults.Items.Add(f);
}
progressBar.Value++;
lbProgress.Text = "Processing Word Documents " + ((int)((float)progressBar.Value / (float)progressBar.Maximum * 100)) + "%";
}
}
string TextFromDocument(string file)
{
string newfile = Environment.CurrentDirectory + "\\temp" + Path.GetExtension(file);
uint i;
if (!CopyFile(file, newfile, true)) i = GetLastError();
object nullobj = System.Reflection.Missing.Value;
word.Application wordApp = new word.Application();
word.Document doc = wordApp.Documents.Open(newfile, false);
doc.ActiveWindow.Selection.WholeStory();
doc.ActiveWindow.Selection.Copy();
string text = doc.Content.Text;
doc.Close(ref nullobj, ref nullobj, ref nullobj);
wordApp.Quit(ref nullobj, ref nullobj, ref nullobj);
File.Delete(newfile);
return text;
}
private void lvResults_DoubleClick(object sender, EventArgs e)
{
Process.Start(lvResults.SelectedItems[0].Text);
lvResults.SelectedItems[0].ForeColor = Color.Purple;
}
private void btnBrowse_Click(object sender, EventArgs e)
{
FolderBrowserDialog fd = new FolderBrowserDialog();
if (fd.ShowDialog() == DialogResult.OK)
{
tbDirectory.Text = fd.SelectedPath;
btnSearch.Enabled = true;
}
}
}
}
Thanks in advance!
Upvotes: 0
Views: 1713
Reputation: 612854
[DllImport("kernel32.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFile(
[MarshalAs(UnmanagedType.LPStr)] string lpExistingFileName,
[MarshalAs(UnmanagedType.LPStr)] string lpNewFileName,
[MarshalAs(UnmanagedType.Bool)] bool bFailIfExists);
In the DllImport
declaration you select the CharSet.Unicode
character set. This will mean that the p/invoke function will be bound to CopyFileW
.
But then you subsequently instruct the marshaller to marshal the parameters as LPStr
, ANSI strings. This is the reason why the function always fails.
A correct p/invoke would be:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CopyFile(string lpExistingFileName, string lpNewFileName,
bool bFailIfExists);
You absolutely should not p/invoke GetLastError
. Instead use Marshal.GetLastWin32Error
for the reasons described in the documentation.
Upvotes: 5