C# Visual Studio 2008 Reference to system32.dll ... how? - c#

I need the reference system32/shell32.dll as I use some shell functions to read out the recycling bin. I tried "Add Reference --> COM --> Microsoft Shell Controls and Automatation" and "Add Reference --> Browse ---> [going to the system32/shell32.dll directly]. Both adds the shell32 reference to my references. But when I look at the properties, I see the path of the reference looks like this: "C:\Users\Tim\Documents\Visual Studio 2008\Projects\Wing\FileWing\obj\Debug\Interop.Shell32.dll" ...
I'll not deploy this \obj\Debug\ path to my installer. So how can I reference the end-users shell32.dll directly? Is there a way? Why does VS2008 create this strange path? Can I change this path so it doesn't sit in this strange subfolder?
Hmmm. Okay after revisiting PInvoke, I'm sure that I don't quite get it :-/
Let me illustrate the code I need to handle. I'm digging though the recycling bin and seek for a item that I want to recover. Is there any way NOT fighting though the PInvoke to get this done?
private void recoverRecyclerBinEntry(string fileName, int size)
{
try
{
Shell Shl = new Shell();
Folder Recycler = Shl.NameSpace(10);
// scans through all the recyclers entries till the one to recover has been found
for (int i = 0; i < Recycler.Items().Count; i++)
{
FolderItem FI = Recycler.Items().Item(i);
string FileName = Recycler.GetDetailsOf(FI, 0);
if (Path.GetExtension(FileName) == "")
FileName += Path.GetExtension(FI.Path);
//Necessary for systems with hidden file extensions.
string FilePath = Recycler.GetDetailsOf(FI, 1);
string combinedPath = Path.Combine(FilePath, FileName);
if (size == FI.Size && fileName == combinedPath)
{
Debug.Write("Match found. Restoring " + combinedPath + "...");
Undelete(FI);
Debug.WriteLine("done.");
}
else
{
Debug.WriteLine("No match");
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.StackTrace);
}
}
private bool Undelete(FolderItem Item)
{
try
{
foreach (FolderItemVerb FIVerb in Item.Verbs())
{
if (
(FIVerb.Name.ToUpper().Contains("WIEDERHERSTELLEN")) ||
(FIVerb.Name.ToUpper().Contains("ESTORE")) ||
(FIVerb.Name.ToUpper().Contains("NDELETE"))
)
{
FIVerb.DoIt();
return true;
}
}
//execute the first one:
Item.Verbs().Item(0).DoIt();
return true;
}
catch (Exception)
{
Debug.WriteLine("ERROR undeleting");
return false;
}
}

I believe you are looking for P/Invoke (Platform Invoke)
Once you get the method for including and using the DLLs down, you can visit pinvoke.net to get specific code snippets for using certain methods.

Are you just using DllImport to access functionality in shell32/kernel32? If so, you don't need to add a reference.
For example:
[DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern bool MoveFile(String src, String dst);
Here's a tutorial on using platform invoke and here's an MSDN article.

After you add the dll reference using VS 2008, you can open the properties for the .dll.
Make sure Copy Local is set to True.
If that doesn't work another solution is to add the .dll as an item to you project, and make is as content, and tell it to copy to the output directory.

Related

InstallShield Dynamic File Linking can't overwrite

I'm working on an InstallShield project and want to implement dynamic file linking to some files so that they always replace the older ones when being installed. The "always overwrite" option is not available while dynamic linking, and I can't find it in InstallShield. This still doesn't work even after I tried to integrate it in the setup.rul using a c# dll.
This is the c# dll that creates a dll called "OverwriteProfilesFiles.dll" and this dll is declared as a SetupFile of InstallShield and moved to "supportDirPath" when I'm installing it:
namespace MoveProfilesFilesOverwriting
{
[ComVisible(true)]
public class MoveFiles
{
[ComVisible(true)]
public bool MoveProfilesFiles()
{
try
{
var source = #"..\FilesCommon\Profiles";
var dest = #"C:\ProgramData\ProgramName\Profiles\PersistentData\Setup\Definitions";
CopyFilesRecursively(source, dest);
return true;
}
catch
{
return false;
}
}
private static void CopyFilesRecursively(string sourcePath, string targetPath)
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath));
}
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories))
{
File.Copy(newPath, newPath.Replace(sourcePath, targetPath), true);
}
}
}
}
And this is the setup.rul function:
// *****************************************************************
// Move Profiles Files
// *****************************************************************
function MoveProfilesFiles(hMSI)
STRING sDLL, szClassName, supportDirPath, returnValue, installerFileName;
STRING subStr;
BOOL callValue;
INT nLength;
OBJECT oInstHelp;
begin
nLength = 256;
MsiGetProperty(hMSI, "SUPPORTDIR", supportDirPath, nLength);
sDLL = supportDirPath ^ "OverwriteProfilesFiles.dll";
szClassName = "MoveProfilesFilesOverwriting.MoveFiles";
try
set oInstHelp = DotNetCoCreateObject(sDLL, szClassName, "");
catch
SprintfBox (INFORMATION, "Error","Error while loading OverwriteHCCUFiles.dll: %i\n\n%s\n\n%s", Err.Number, Err.Description, Err.LastDllError);
endcatch;
try
callValue = oInstHelp.MoveProfilesFiles();
catch
SprintfBox (INFORMATION, "Error","Error : %i\n\n%s\n\n%s", Err.Number, Err.Description, Err.LastDllError);
endcatch;
end;
There are no errors when I try to install the.exe file, however the files aren't copied to the folder. Any suggestions on how to make this function better or another approach to use dynamic file linking with the always overwrite option are welcome.
This is the limitation when you use dynamic file linking. Refer this - https://docs.revenera.com/installshield21helplib/helplibrary/DFL-Limitations.htm#organizingfiles_2971526177_1186025
When you use "Always Overwrite" feature for static files, Installshield puts highest version(65535.0.0.0) so that it always replaces files on target system using file versioning rules.
So, In order to achieve same behavior in dynamic link settings, you need to modify .msi file using vbscript/powershell to update version column in File table externally(Build system or manually). After this, you can digitally sign the .msi file. That's it.
Handling this through separate copy operations(as per above setup.rul function) will complicate the future upgrades/patching. This should be avoided.

What need I do to get this code to work in a Portable Class Library?

I'm wondering if the Portable Class Library is even more restricted in functionality than the Compact Framework.
I'm trying to port a CF/Windows CE app (runs on a handheld device) to a Xamarin solution that will target Android, iOS, Windows Phone, and perhaps other things.
One of the problems I run into, though, is that this legacy code (which works under CF):
public static List<string> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
string dirName = startingDir;
// call it like so: GetXMLFiles("ABC", "\\"); <= I think the double-whack is what I need for Windows CE device...am I right?
var fileNames = new List<String>();
try
{
foreach (string f in Directory.GetFiles(dirName))
{
string extension = Path.GetExtension(f);
if (extension != null)
{
string ext = extension.ToUpper();
string fileNameOnly = Path.GetFileNameWithoutExtension(f);
if (fileNameOnly != null &&
((ext.Equals(EXTENSION, StringComparison.OrdinalIgnoreCase)) &&
(fileNameOnly.Contains(fileType))))
{
fileNames.Add(f);
}
}
}
foreach (string d in Directory.GetDirectories(dirName))
{
fileNames.AddRange(GetXMLFiles(fileType, d));
// from Brad Rem's answer here: http://stackoverflow.com/questions/22186198/why-is-this-function-returning-nothing-although-there-is-a-match/22186351?noredirect=1#22186351
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return fileNames;
}
...won't compile in the Xamarin/CPL solution. I get, "The name 'Directory' does not exist in the current context" and right-clicking that word does not afford a "resolve" option.
Is there a way to get PCL to recognize "Directory" or must I completely rewrite the code? If the latter, does anybody have any suggestions on what to do/use in its stead?
Relatedly, is there an URL that will show me what is [not] available in PCL and/or a site that will show how much of a provided block of code is "PCL-ready"?
UPDATE
The first image in this article is very illuminating. Later on, it specifically talks about "Directory" not being available in the PCL scenario.
UPDATE 2
I downloaded the PCLStorage package referenced by Daniel Plaisted below to allow me to access the file system within a PCL project.
Using the sample code at the start of the download page [http://pclstorage.codeplex.com/] as a starting point, I've gotten this far:
public async Task<List<string>> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.GetFolderAsync(startingDir, CreationCollisionOption.OpenIfExists); //CreateFolderAsync(startingDir, CreationCollisionOption.OpenIfExists);
List<string> fileNames = await folder.GetFilesAsync(EXTENSION);
return fileNames;
}
...but "EXTENSION" as the arg to GetFilesAsync() is not right. I get with this, "Argument 1: cannot convert from 'string' to 'System.Threading.CancellationToken'"
So what need I do to get all the *.XML files the folder?
UPDATE 3
This compiles, but I'm not at all sure it's the right way to do it, besides the fact that it simply gets all the files from the folder, rather than just those that match "*.XML":
public async Task<List<IFile>> GetXMLFiles(string fileType, string startingDir)
{
const string EXTENSION = ".XML";
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.GetFolderAsync(startingDir, System.Threading.CancellationToken.None);
IList<PCLStorage.IFile> fileNames = await folder.GetFilesAsync(System.Threading.CancellationToken.None);
return fileNames.ToList();
}
Since in a PCL I was unable to get a StreamWriter from a string (it required a stream), I created a simple interface to get some of the data from the platform implementation. You can also do this with DirectoryInfo and FileInfo.
https://github.com/sami1971/SimplyMobile/blob/master/Core/SimplyMobile.Text/IStreamLocator.cs
The implementation is really simple as well, only needs one single compiler flag for WP8:
https://github.com/sami1971/SimplyMobile/blob/master/WP8/SimplyMobile.Text.Platform/StreamLocator.cs
Recursively search for *.XML files:
private static void PrintDirectory(IStreamLocator locator, string dir)
{
foreach (var file in locator.GetFileNames(dir, "*.XML"))
{
System.Diagnostics.Debug.WriteLine(file);
}
foreach (var di in locator.GetFolderNames(dir, "*"))
{
PrintDirectory(locator, di);
}
}
Windows Phone applications do not use the file system of the operating
system and are restricted to using isolated storage to persist and
access files, so this namespace does not provide any additional
functionality.
http://msdn.microsoft.com/en-us/library/windowsphone/develop/system.io%28v=vs.105%29.aspx
Xamarin has a scanner which will give you a rough idea of the portability of your code: http://scan.xamarin.com/
For some guidance on how to deal with non-portable APIs from PCLs, see my blog post: How to Make Portable Class Libraries Work for You
For file IO in particular, you can try my PCL Storage library.
Another option is to use Shim if all your platforms are supported by it.
API coverage for file operations isn't exhaustive, but it gets you a long way. As a bonus, it also gives you access to a bunch of other stuff.

How to close a file in Autocad using C# keeping acad.exe running?

I am using visual studio 2010 and I am having a .DWG file which I want to open in autocad. Till now I have used this.
Process p = new Process();
ProcessStartInfo s = new ProcessStartInfo("D:/Test File/" + fileName);
p.StartInfo = s;
p.Start();
But what I want is to close the file inside the Autocad but not the autocad itself. (Means atocad.exe should be kept running).
Till now I hve used this but its closing the acad.exe not the file.
foreach (Process Proc in Process.GetProcesses())
{
if (Proc.ProcessName.Equals("acad"))
{
Proc.CloseMainWindow();
Proc.Kill();
}
}
Take the Autocad .NET libraries from Autodesk Sites (http://usa.autodesk.com/adsk/servlet/index?id=773204&siteID=123112)
Then you will be able to use Application and Document classes.
They will give you full control over opening and closing documents within the application.
You can find many articles on that, and can ask further questions.
AutoCAD does have an api. there are 4 assemblys. Two for in-process and two for COM.
inprocess :
acdbmgd.dll
acmgd.dll
COMInterop :
Autodesk.Autocad.Interop.dll
Autodesk.Autocad.Interop.Common.dll
this is a method that will open a new instance of AutoCAD or it will connect to an existing running instance of AutoCAD.
you will need to load these .dlls into your project references.
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
namespace YourNameSpace {
public class YourClass {
AcadApplication AcApp;
private const string progID = "AutoCAD.Application.18.2";// this is AutoCAD 2012 program id
private string profileName = "<<Unnamed Profile>>";
private const string acadPath = #"C:\Program Files\Autodesk\AutoCAD 2012 - English\acad.exe";
public void GetAcApp()
{
try
{
AcApp = (AcadApplication)Marshal.GetActiveObject(progID);
} catch {
try {
var acadProcess = new Process();
acadProcess.StartInfo.Arguments = string.Format("/nologo /p \"{0}\"", profileName);
acadProcess.StartInfo.FileName = (#acadPath);
acadProcess.Start();
while(AcApp == null)
{
try { AcApp = (AcadApplication)Marshal.GetActiveObject(progID); }
catch { }
}
} catch(COMException) {
MessageBox.Show(String.Format("Cannot create object of type \"{0}\"",progID));
}
}
try {
int i = 0;
var appState = AcApp.GetAcadState();
while (!appState.IsQuiescent)
{
if(i == 120)
{
Application.Exit();
}
// Wait .25s
Thread.Sleep(250);
i++;
}
if(AcApp != null){
// set visibility
AcApp.Visible = true;
}
} catch (COMException err) {
if(err.ErrorCode.ToString() == "-2147417846"){
Thread.Sleep(5000);
}
}
}
}
}
closeing it is as simple as
Application.Exit();
and forgive the code. its atrocious, this was one of my first methods when i just started developing...
I doubt you will be able to do this unless AutoCAD has an API that you can hook into and ask it to close the file for you.
Your c# app can only do things to the process (acad.exe) , it doesn't have access to the internal operations of that process.
Also, you shouldn't use Kill unless the process has become unresponsive and certainly not immediately after CloseMainWindow.
CloseMainWindow is the polite way to ask an application to close itself. Kill is like pulling the power lead from the socket. You aren't giving it the chance to clean up after itself and exit cleanly.
There is one other possibility - this will only work if your C# code is running on the same machine as the AutoCAD process and it is not really recommended, but, if you are really stuck and are prepared to put up with the hassle of window switching you can send key strokes to an application using the SendKeys command.
MSDN articles here:
http://msdn.microsoft.com/EN-US/library/ms171548(v=VS.110,d=hv.2).aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx
Using this you could send the key strokes to simulate the user using the menu commands to close the file.
To perform the closing of file, best way out is to follow the steps at this ObjectARX SDK for c# and change the following code with the below code.
[CommandMethod("CD", CommandFlags.Session)]
static public void CloseDocuments()
{
DocumentCollection docs = Application.DocumentManager;
foreach (Document doc in docs)
{
// First cancel any running command
if (doc.CommandInProgress != "" &&
doc.CommandInProgress != "CD")
{
AcadDocument oDoc =
(AcadDocument)doc.AcadDocument;
oDoc.SendCommand("\x03\x03");
}
if (doc.IsReadOnly)
{
doc.CloseAndDiscard();
}
else
{
// Activate the document, so we can check DBMOD
if (docs.MdiActiveDocument != doc)
{
docs.MdiActiveDocument = doc;
}
int isModified =
System.Convert.ToInt32(
Application.GetSystemVariable("DBMOD")
);
// No need to save if not modified
if (isModified == 0)
{
doc.CloseAndDiscard();
}
else
{
// This may create documents in strange places
doc.CloseAndSave(doc.Name);
}
}
}

Access denied - Trying to delete all files in a folder

I'm currently trying to delete all files in a folder (Recently opened files), but without any luck, I get the message: "Access to the path 'C:\Users\User\Recent' is denied." . I've been looking around to see if there were any solutions, but unfortunately I can't find anything.
String recent = Environment.ExpandEnvironmentVariables("%USERPROFILE%") + "\\Recent";
EmptyFolderContents(recent);
private void EmptyFolderContents(string folderName)
{
foreach (var Folder in Directory.GetDirectories(folderName))
{
try
{
Directory.Delete(Folder, true);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
foreach (var Files in Directory.GetFiles(folderName))
{
try
{
File.Delete(Files);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
}
The reason you are getting the Access Denied error is because you can't just delete files from that folder. They are virtual paths to real files. There is probably a better way to do what you are doing.
Here is an alternative that I found here. It uses WinAPI, which is never fun, but it works.
//you'll need to add this.
using System.Runtime.InteropServices;
[DllImport("shell32.dll")]
public static extern void SHAddToRecentDocs(ShellAddToRecentDocsFlags flag, IntPtr pidl);
public enum ShellAddToRecentDocsFlags
{
Pidl = 0x001,
Path = 0x002,
}
//then call this from your method
SHAddToRecentDocs(ShellAddToRecentDocsFlags.Pidl, IntPtr.Zero);
Your error message seems to show that you're missing a backslash:
Access to the path 'C:Users\User\Recent' is denied.
(after the C:)
I Use Permissions Time Machine v1.1 to restore default permissions and remove "Access is denied" message for folder or files or registry keys or windows services or wmi objects it's free and fast and easy
download it from amyd projects blog

hijack program’s command to run notepad

I have a utility programs’s EXE file, when i run this file there is a winform only and there is button when we click on it, it run windows’s notepad. Now I want to hijack this program’s command to run notepad and instead of running notepad I want to run MS Word. I know C# and VB.NET. What I need to do this ?
You can try to add in folder with this program your own program called notepad.exe that should do only one thing: run word.
If you want to do it programatically in C then you should read this page - maybe it helps: Intercepted: Windows Hacking via DLL Redirection
You can use a trick to replace programs with another by making changes to the registry. This will work even if the program you are running uses absolute paths to run notepad. It overrides any instance of the running program with the chosen one no matter where it resides. And you won't have to patch the file. The key you'd be interested in is:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
Add a key with the name of the program and add a Debugger string with the path to the program you want to replace it with. Of course you need to have permissions to make the necessary modifications. This page explains how you can replace Windows Notepad with another program. You can apply the same process here.
Though you'll probably not want to have this permanent change, so you can write up a program to temporarily add/change the key, run your program then change it back. Here's a complete one I just whipped up to temporarily replace Notepad with Word for a demonstration. Seems to work perfectly fine (though as always, use at your own risk). Just make all the necessary changes to fit your situation.
using System.Diagnostics;
using Microsoft.Win32;
namespace ProgramLauncher
{
class Program
{
// change the following constants as needed
const string PROGRAM_NAME = #"notepad.exe";
const string REPLACEMENT_PATH = #"C:\Program Files (x86)\Microsoft Office\Office12\WINWORD.EXE";
const string RUNNING_PATH = #"C:\Windows\notepad.exe";
// root key
const string KEY = #"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options";
static void Main(string[] args)
{
using (var rootKey = Registry.LocalMachine.OpenSubKey(KEY, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
var oldPath = default(string);
var needsRestoration = false;
try
{
oldPath = BackupKey(rootKey, PROGRAM_NAME, REPLACEMENT_PATH);
needsRestoration = true;
Process.Start(RUNNING_PATH).WaitForExit();
}
finally
{
if (needsRestoration)
RestoreKey(rootKey, PROGRAM_NAME, oldPath);
}
}
}
static string BackupKey(RegistryKey rootKey, string programName, string newPath)
{
Debug.Assert(rootKey != null);
Debug.Assert(!string.IsNullOrEmpty(programName));
Debug.Assert(!string.IsNullOrEmpty(newPath) && System.IO.File.Exists(newPath));
if (newPath.Contains(" "))
newPath = string.Format("\"{0}\"", newPath);
using (var programKey = rootKey.CreateSubKey(programName, RegistryKeyPermissionCheck.ReadWriteSubTree))
{
var oldDebugger = programKey.GetValue("Debugger") as string;
programKey.SetValue("Debugger", newPath, RegistryValueKind.String);
return oldDebugger;
}
}
static void RestoreKey(RegistryKey rootKey, string programName, string oldPath)
{
Debug.Assert(rootKey != null);
Debug.Assert(!string.IsNullOrEmpty(programName));
if (oldPath != null)
{
using (var programKey = rootKey.OpenSubKey(programName, RegistryKeyPermissionCheck.ReadWriteSubTree))
programKey.SetValue("Debugger", oldPath);
}
else
{
rootKey.DeleteSubKey(programName);
}
}
}
}

Categories

Resources