Revit Copy addin dll at shutdown - batch-file

I am working on creating a revit addin and I want to have it automatically pull a copy ofthe .dll and.addin files at shutdown using a batch file. By themselves the code and the batch file routines work correctly but when I have them running with each other I get a have a sharing violation for copying the .dll file. Can anyone tell me how I can get around the sharing violation? The purpose is to deploy these two files to all users and copy the file updates to their computer when they shut down Revit.
public Result OnShutdown(UIControlledApplication application)
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = "S:\\Revit 2015\\Addins\\Revit Tabs\\2015_RevitTab.bat";
proc.StartInfo.WorkingDirectory = "S:\\Revit 2015\\Addins\\Revit Tabs\\";
proc.Start();
return Result.Succeeded;
}
And here is the copy syntax
xcopy "S:\Revit 2015\Addins\Revit Tabs\Revit Tabs.addin" "C:\ProgramData\Autodesk\Revit\Addins\2015" /y
xcopy "S:\Revit 2015\Addins\Revit Tabs\Revit Tabs\bin\Debug\Revit Tabs.dll" "C:\ProgramData\Autodesk\Revit\Addins\2015" /y

You could add a call to your own stand-alone utility exe that monitors whether the current Revit process is still alive, and thenexecutes the add-in DLL copy process once Revit really is gone.

I wanted to same auto-update process and after a bit of trial and error I found some code that worked for me. Hopefully, you can use it or improve it.
I have ribbon.addin, ribbon.dll ("Ribbon") and commands.dll ("Commands") files. All files are installed as part of the deployment into the "%appdata%\Autodesk\Revit\Addins\2016" folder ("Local"). It's important that these are installed in the "%appdata%" folder and not the "%programdata%\Autodesk\Revit\Addins\2016" folder because of write protection issues!
The Ribbon addin is only for checking which version of the Commands is currently in the Local folder and if that's out-of-date from the Commands file I have in a shared network folder ("Shared"). Because of security, I can't read the AssemblyVersion of the Local DLL or the Shared DLL. To get around this I have a TXT file in the Local folder that has the AssemblyVersion as the first line and, in the Shared folder I have another TXT file (where I actually have the "About" information of the Commands addin) which has the Shared Commands AssemblyVersion as the first line.
So my Ribbon OnStartup(UIControlledApplication a) code checks the TXT files using System.IO.StreamReader. If the Local file is out-of-date it updates the Local TXT and DLL files with this c#:
try
{
string AddinsDir = a.ControlledApplication.CurrentUserAddinsLocation + #"\";
string tempDir = System.IO.Path.GetTempPath();
StreamWriter myStream = new StreamWriter(tempDir + "Commands.txt", false, System.Text.Encoding.Default);
myStream.WriteLine(AssemblyVersion);
//AssemblyVersion is the first line of the Shared Commands TXT file we read
myStream.Close();
File.Copy(tempDir + "Commands.txt", AddinsDir + "Commands.txt", true);
File.Delete(tempDir + "Commands.txt");
File.Delete(AddinsDir + "Commands.dll");
File.Copy(SharedPath + "Commands.dll", AddinsDir + "Commands.dll", true);
//SharedPath is the Shared folder
}
catch (Exception e)
{
TaskDialog.Show("Error Loading Ribbon", "There was an error loading the Ribbon. Please contact the BIM Manager for assistance.\n\n" + e.Message);
return Result.Failed;
}
If, at this point the code is still running the file is up-to-date and it's time to load it:
Assembly Commands = Assembly.LoadFrom(AddinsDir + "Commands.dll");
Type type = Commands.GetType("Commands.App");
//Commands.App is my class where my Ribbon is created and Events are registered
object instanceOfCommands = Activator.CreateInstance(type, new object[] { a });
return Result.Succeeded;
My plan for Revit 2017 deployment is to create my custom Ribbon in the Ribbon.dll so I can have my "About" button there and accessible at all times. Then, I'll add a button in the "About" dialog box that would manually update the Local Commands DLL.
I hope that helps!!

Related

Open file in the default application WinForms (.NET Core) [duplicate]

i want to ask for help with opening a file from c# app with associated app.
I tried this:
ProcessStartInfo pi = new ProcessStartInfo(file);
pi.Arguments = Path.GetFileName(file);
pi.UseShellExecute = true;
pi.WorkingDirectory = Path.GetDirectoryName(file);
pi.FileName = file;
pi.Verb = "OPEN";
Process.Start(pi);
or this:
Process.Start(file);
where string file in both examples represents full path to the file trying to open. Now, everything is working well, except the (jpg) images with ACDSee app. Irfanview associations works well, MS office documents too. After trying to open the jpg image associated with acdsee it just runs the acdsee in the notification area and does not open the file.
I discovered, that in the registry CLASSES_ROOT for *.jpg images, there is an ACDSee.JPG value as associated app, and under this key there is in the shell->Open->Command a path:
"C:\Program Files\ACD Systems\ACDSee\ACDSee.exe" /dde
and I thing that this weird /dde is the reason, why i cannot open the file. I realized that in the same reg key shell->Open there is some DDEExec key entry with value [open("%1")]
For Irfan view or other checked app there is not a ddeexec, just the normal command like
"C:\Program Files (x86)\IrfanView\i_view32.exe" "%1"
that can be run from command line after swaping the %1 for file name, but I could not run the command from acdsee entry in the command line :(
So my question is, how can I set up the ProcessStartInfo object to ensure that it will run all the files as it would be in the explorer by doubleclick, the standards and this DDEExec ones? Is there something other like DDEExec that I shoul be aware of?
thanks and sorry for my EN
UPDATE: because this question still gets upvotes, I want to clarify that accepted answer works. I only had problem with old version of ACDSee and not with the Process.Start command or with the jpg extension.
Just write
System.Diagnostics.Process.Start(#"file path");
example
System.Diagnostics.Process.Start(#"C:\foo.jpg");
System.Diagnostics.Process.Start(#"C:\foo.doc");
System.Diagnostics.Process.Start(#"C:\foo.dxf");
...
And shell will run associated program reading it from the registry, like usual double click does.
In .Net Core (as of v2.2) it should be:
new Process
{
StartInfo = new ProcessStartInfo(#"file path")
{
UseShellExecute = true
}
}.Start();
Related github issue can be found here
This is an old thread but just in case anyone comes across it like I did.
pi.FileName needs to be set to the file name (and possibly full path to file ) of the executable you want to use to open your file. The below code works for me to open a video file with VLC.
var path = files[currentIndex].fileName;
var pi = new ProcessStartInfo(path)
{
Arguments = Path.GetFileName(path),
UseShellExecute = true,
WorkingDirectory = Path.GetDirectoryName(path),
FileName = "C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe",
Verb = "OPEN"
};
Process.Start(pi)
Tigran's answer works but will use windows' default application to open your file, so using ProcessStartInfo may be useful if you want to open the file with an application that is not the default.

WPF - Attach Folder that has many files with clickonce deployment to be installed in user C drive

I am developing a WPF application, that has a function to run the "CMD" in user pc and navigate to one folder "platform-tools" that included in the application files and execute a command.
string Request = " /c" + "cd../../&cd platform-tools& adb reboot ";
Process procc = new Process();
ProcessStartInfo procStartInfo2 = new ProcessStartInfo(#"cmd.exe", Request);
As we know, when the user install the application in his PC, the application will be located in C:\Users\""UserName\AppData\Local\Apps\2.0\"random name like: JBJHV6HG7HG"
so its difficult to know where is exactly the "platform-tools" will be installed.
My question is: is there any way i can know how to reach the platform-tools folder by my "Request" in order to rung the adb command?
or
is there a way to install the "platform-tools" in different location like "User's desktop" then i can change the "CD" command in CMD to navigate to user's desktop or C drive?
Using the ClickOnce, you won't be able to change the destination install folder due some security features and so on...
you can find out more Here
You can get the path of your executing process, and concatenate the folder name to reach the "platform-tools" folder:
//There's two ways to get the current file address from your application (in the end both ends in the same):
//There's two ways to get the current file address from your application (in the end both ends in the same):
//getting the filename by the process
var cc = Process.GetCurrentProcess().MainModule.FileName;
//getting the filename by the executing assembly
var dd = System.Reflection.Assembly.GetExecutingAssembly().Location;
//getting the path for that file name
string assemblyPath = Path.GetDirectoryName(cc);
var platformTools = string.Concat(assemblyPath, #"/platform-tools/someprocess.exe");
Process.Start(platformTools);

Zip a folder using SSIS

I am trying to zip a Folder in SSIS, there are 12 files in the source folder and I need to zipthat folder. I can get the files to zip fine my problem is the folders.
I have to use winzip to create the zipped packages.
Can anyone point me to a good tutorial. I haven't been able to implement any of the samples that I have found.
Thanks
Adding a Script Task, yuo can use the ZipFile (class) here reference, you must refer to the System.IO.Compression.FileSystem assembly in the project (.NET Framework 4.5).
You need to provide to the Script Task the folder to be zipped and the name of the compressed folder as ReadOnlyVariables (to be added in the tab ReadOnlyVariables)
These two variables must be defined in the Variables tab (String type) of the package and can be changed dynamically through a cycle (eg. for each)
I use these two variables:
sFolderCompressed - the folder '.zip' that you want to obtain eg. C:\folder1\result.zip
sFolderSource - the source folder containing the files affected eg. C:\folder1\folder2
The script is made using c#, choose Script Language: Microsoft Visual C#
This is the code to be added in the Main method:
using System.IO.Compression;
public void Main()
{
try
{
string zipPath = (string)Dts.Variables["User::sFolderCompressed"].Value;
string startPath = (string)Dts.Variables["User::sFolderSource"].Value;
ZipFile.CreateFromDirectory(startPath, zipPath);
}
catch (Exception objException)
{
Dts.TaskResult = (int)ScriptResults.Failure;
// Log the exception
}
Dts.TaskResult = (int)ScriptResults.Success;
}
I hope can help.
Try using 7zip it is free. Take a look at 7zip command line user guide it contains all commands you need
And use a script task or an execute process task to achieve this. Also there are other useful links:
https://www.dotnetperls.com/7-zip-examples
UPDATE 1
you can follow this link for winzip:
http://www.vbforums.com/showthread.php?202918-Well-WinZip-Command-Line-Folders-to-Zip-keep-folder-structure-
In the link above they suggested using this command:
wzzip "c:\Test.zip" "c:\myfolder" -exPR
Write these things in bat file...
"C:\Program Files\WinZip\WINZIP64.EXE" -a "C:\Desktop\destination_folder\Sample.zip" "C:\Desktop\Sample"
In Execute process task:
Mention the location of bat file in Execute process Task-->Process-->Executable.
It's work fine.

When starting a process how do I set the directory for that process to read/write files?

In a WPF project this line is very simple to start mspaint with a given filename
Process.Start("mspaint.exe", filename)
While mspaint.exe will work with 'filename' in it's directory, if I try to open other files or do a 'SaveAs', mspaint.exe is looking at the Visual Studio \bin directory where the application was compiled to. Even if I move the .exe elsewhere, it keeps looking at the \bin location.
I tried the following:
Dim process1StartInfo As New ProcessStartInfo
process1StartInfo.WorkingDirectory = "C:\Users\theuser\Pictures"
process1StartInfo.FileName = "mspaint.exe"
process1StartInfo.Arguments = filename
process1StartInfo.UseShellExecute = False
Dim process1 = Process.Start(process1StartInfo)
I thought setting .WorkingDirectory would change the behavior but it does not.
Is it possible to and how do I change the directory that mspaint.exe is looking at when it is launched from within an application? Especially after the application is compiled and moved.

How do I call a batch file from an MSI

I have an msi installer that needs to call a few batch files to finish the install procedure. The batch file copies extra files from the installer to a few directories and then modifies permissions on several of those directories. We want to continue using the batch files because there is not a lot of time left in our development schedule. I am not using WIX.
If possible I would like to capture the output of the batch as it goes and write it to a log file.
Found bellow is the code I am using to try to run the batch file from a custom action. It opens a cmd window, runs for a while but never seems to finish. If I run the same batch files directly from the command prompt they work.
//Set the environment to the directory containing the bat files
ProcessStartInfo info = new ProcessStartInfo(batch);
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = false;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
if (!string.IsNullOrEmpty(argument))
info.Arguments = argument;
Process process = new Process();
process.StartInfo = info;
process.Start();
// Capture the standard error and standard output
What am I doing wrong?
I believe you'll need to create a custom action. See this question.
Many anti-virus programs may stop execution of .BAT files during an installation process, you should really be doing this using standard Windows Installer functionality or as a C++ Custom Action

Resources