Hows the following code run in autocad? - c#

Hello this is my code and i don't know how to run and get output of this code. Please suggest me the answer for this.And I want to create command for autocad using this code so suggest me according to this requirement.
using System;
using System.IO;
using System.Globalization;
using UDC;
using AutoCAD = Autodesk.AutoCAD.Interop;
namespace AutoCADtoPDF
{
class Program
{
static void PrintAutoCADtoPDF(string AutoCADFilePath)
{
//Create a UDC object and get its interfaces
IUDC objUDC = new APIWrapper();
IUDCPrinter Printer = objUDC.get_Printers("Universal Document Converter");
IProfile Profile = Printer.Profile;
//Use Universal Document Converter API to change settings of converterd drawing
//Load profile located in folder "%APPDATA%\UDC Profiles".
//Value of %APPDATA% variable should be received using Environment.GetFolderPath method.
//Or you can move default profiles into a folder you prefer.
string AppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string ProfilePath = Path.Combine(AppDataPath, #"UDC Profiles\Drawing to PDF.xml");
Profile.Load(ProfilePath);
Profile.OutputLocation.Mode = LocationModeID.LM_PREDEFINED;
Profile.OutputLocation.FolderPath = #"c:\UDC Output Files";
Profile.PostProcessing.Mode = PostProcessingModeID.PP_OPEN_FOLDER;
AutoCAD.AcadApplication App = new AutoCAD.AcadApplicationClass();
double Version = double.Parse(App.Version.Substring(0, 4), new CultureInfo("en-US"));
//Open drawing from file
Object ReadOnly = false;
Object Password = Type.Missing;
AutoCAD.AcadDocument Doc = App.Documents.Open(AutoCADFilePath, ReadOnly, Password);
//AutoCAD.Common.AcadPaperSpace ActiveSpace;
AutoCAD.Common.AcadLayout Layout;
//Change AutoCAD preferences for scaling the drawing to page
if (Doc.ActiveSpace == 0)
Layout = Doc.PaperSpace.Layout;
else
Layout = Doc.ModelSpace.Layout;
Layout.PlotType = AutoCAD.Common.AcPlotType.acExtents;
Layout.UseStandardScale = true;
Layout.StandardScale = AutoCAD.Common.AcPlotScale.acScaleToFit;
Layout.CenterPlot = true;
Object nBACKGROUNDPLOT = 0, nFILEDIA = 0, nCMDDIA = 0;
if (Version >= 16.1f)
{
nBACKGROUNDPLOT = Doc.GetVariable("BACKGROUNDPLOT");
nFILEDIA = Doc.GetVariable("FILEDIA");
nCMDDIA = Doc.GetVariable("CMDDIA");
Object xNull = 0;
Doc.SetVariable("BACKGROUNDPLOT", xNull);
Doc.SetVariable("FILEDIA", xNull);
Doc.SetVariable("CMDDIA", xNull);
}
Doc.Plot.QuietErrorMode = true;
//Plot the drawing
Doc.Plot.PlotToDevice("Universal Document Converter");
if (Version >= 16.1f)
{
//Restore AutoCAD default preferences
Doc.SetVariable("BACKGROUNDPLOT", nBACKGROUNDPLOT);
Doc.SetVariable("FILEDIA", nFILEDIA);
Doc.SetVariable("CMDDIA", nCMDDIA);
}
//Close drawing
Object SaveChanges = false;
Doc.Close(SaveChanges, Type.Missing);
//Close Autodesk AutoCAD
App.Quit();
}
static void Main(string[] args)
{
string TestFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFile.dwg");
PrintAutoCADtoPDF(TestFilePath);
}
}
}

Did you read the comments in the original source ?
This code is a example of using a third part application name Universal Document Converter (UDC) to build a standalone application (exe) to print the active space of a dwg file into a pdf file.
It requires the UDC software to be installed.
It cannot be transformed into an AutoCAD plugin (dll with CommandMethod).
You certainly can get more informations about this with the UDC Support.
You will not learn .NET and AutoCAD API by copying codes found on the web that you do not understand and asking someone here or elsewhere to modify them to suit your needs.

first: add a using to the runtime.
using Autodesk.AutoCAD.Runtime;
next: Add an attribute to your method.
[CommandMethod("YOURCOMMANDNAMEINAUTOCAD")]
Last: Your class and method need to be public, for AutoCAD to see them.
Update: (Very last): your Method cannot take parameters.

Related

Delete the log file after archiving using NLog C#

I want to archive log files periodically(for every hour) from "Logs" folder to "Archive" folder and then delete those archived files from "logs" folder immediately. Can we achieve this using NLog?
Currently, I am using the below c# code for archiving, but I am not seeing the desired output. We are using Nlog version 4.7.11.
target.FileName = #"C:\Logs\Log-${date:format=yyyy-MM-dd-hh}.log";
target.ArchiveFileName = #"C:\Archives\Log-${date:format=yyyy-MM-dd-hh}.log";
target.ArchiveEvery = FileArchivePeriod.Hour;
target.ArchiveOldFileOnStartup = true;
target.DeleteOldFileOnStartup = true;
target.MaxArchiveDays = 10;
target.ArchiveNumbering = ArchiveNumberingMode.Date;
target.MaxArchiveFiles = 50;
target.ArchiveDateFormat = "yyyy-mmm-dd hh-mm";
target.EnableArchiveFileCompression = true;
NLog supports 2 file-archive-modes:
Static FileName Archive-mode, where ArchiveEvery controls when to roll.
Dynamic FileName Archive-mode, where FileName contains ${date} or ${shortdate} (Rolls automatically)
NLog does not support mixing these 2 file-archive-modes. If you want files to be moved into the Archive-folder, then you must use static FileName:
target.FileName = #"C:\Logs\App.log";
target.ArchiveFileName = #"C:\Archives\App-{#}.log.zip";
target.ArchiveEvery = FileArchivePeriod.Hour;
target.ArchiveOldFileOnStartup = true;
target.DeleteOldFileOnStartup = true;
target.MaxArchiveDays = 10;
target.ArchiveNumbering = ArchiveNumberingMode.DateAndSequence;
target.MaxArchiveFiles = 50;
target.ArchiveDateFormat = "yyyy-MM-dd-hh";
target.EnableArchiveFileCompression = true;
Alternative you can use dynamic-archive-mode and then use scheduled-task/cron-job to compress/move log-files to the wanted location:
target.FileName = #"C:\Logs\Log-${date:format=yyyy-MM-dd-hh}.log";
target.ArchiveOldFileOnStartup = true;
target.MaxArchiveDays = 10;
target.MaxArchiveFiles = 50;
See also Do not mix dynamic with static-archive-mode
You can extend your NLog method to run some method after logging. Please refer to the following: https://github.com/NLog/NLog/wiki/MethodCall-target.
MethodCall target: Calls the specified static method on each log message and passes contextual parameters to it.
You can create some code that uses System.IO to move and archive your code based on your needs.

Can I store an Ini file in a Resources file?

I have a Windows Forms application, .Net Framework 4.6.1, and I want to store some DB connection data in an Ini file.
I then wanted to store it in the Resources file of the project (so I don't have to copy/paste the file in the Debug and Release folder manually, etc.) as a normal file, but when I tried to compile the program and read the Ini data with ini-parser, the following exception showed up: System.ArgumentException: 'Invalid characters in path access'.
I'm using Properties.Resources where I read the Ini file, so I guessed there would be no problem with the path. Could it be a problem with the Ini file itself?
The content of the Ini file is the following:
[Db]
host = (anIP)
port = (aPort)
db = (aDbName)
user = (aDbUser)
password = (aDbUserPwd)
And my method for reading the data:
public static void ParseIniData()
{
var parser = new FileIniDataParser();
IniData data = parser.ReadFile(Properties.Resources.dbc);
mysqlHost = data["Db"]["host"];
mysqlPort = data["Db"]["port"];
mysqlDb = data["Db"]["db"];
mysqlUser = data["Db"]["user"];
mysqlPwd = data["Db"]["password"];
}
I finally could do it using what #KlausGütter told me in the comments (thanks!).
Instead of using the FileIniDataParser you have to use the StreamIniDataParser, and get the Stream with Assembly.GetManifestResourceStream.
I found this a bit tricky, because using this method you need to set the Build Action in the file you want to read to Embedded Resource.
This file is then added as an embedded resource in compile time and you can retrieve its stream.
So my method ended up the following way:
public static void ParseIniData()
{
var parser = new StreamIniDataParser();
dbcReader = new StreamReader(_Assembly.GetManifestResourceStream("NewsEditor.Resources.dbc.ini"));
IniData data = parser.ReadData(dbcReader);
mysqlHost = data["Db"]["host"];
mysqlPort = data["Db"]["port"];
mysqlDb = data["Db"]["db"];
mysqlUser = data["Db"]["user"];
mysqlPwd = data["Db"]["password"];
}
where _Assembly is a private static attribute: private static Assembly _Assembly = Assembly.GetExecutingAssembly();. This gets you the assembly that's being executed when running the code (you could also use this code directly in the method, but I used the Assembly on another method in my class, so I decided to set an attribute... DRY I guess).

Word Interop: get_AttachedTemplate() returns an incorrect path

I'm writing a C# app that goes through a list of Word documents and changes their attached template using Interop. The idea is that if a bunch of Word documents are pointing to templates on a server that doesn't exist, we can use string replace to change the templates' paths to the correct ones.
Note that each document may have one of several different templates, and therefore I can't just change all of them to a specific path - I must use string replace.
My problem is that my Interop.Word.Document object doesn't return the correct attached template. When I open a Word document in MS Word and go to the templates window, I see that the attached template is a network file template that doesn't exist anymore. That's the path I want to change. But when I use get_AttachedTemplate() in C#, I get the path to another template...
Can anyone help me?
Note: I'm using Microsoft Word 16.0 Object Library.
using System;
using System.IO;
using System.Reflection;
using Microsoft.Office.Interop.Word;
using App = Microsoft.Office.Interop.Word.Application;
using Doc = Microsoft.Office.Interop.Word.Document;
namespace OfficeTemplateCleaner
{
internal class Program
{
private static void Main(string[] args)
{
Console.Write(#"Enter a string to search (e.g. \\old\path\): ");
var stringToFind = Console.ReadLine();
Console.Write($"Enter a string to replace \"{stringToFind}\": ");
var replaceWith = Console.ReadLine();
var files = new[]
{
#"\\path\to\one\test\document.doc"
};
App oWord = new App() { Visible = false };
foreach (var file in files)
{
if (!File.Exists(file))
{
continue;
}
// cache file modification times so that we can revert them to what they were originally
var fileInfo = new FileInfo(file);
var modifyTime = fileInfo.LastWriteTime;
//OBJECT OF MISSING "NULL VALUE"
object oMissing = Missing.Value;
//OBJECTS OF FALSE AND TRUE
object oTrue = true;
object oFalse = false;
//CREATING OBJECTS OF WORD AND DOCUMENT
Doc oWordDoc = new Doc();
//MAKING THE APPLICATION VISIBLE
oWord.Visible = true;
//ADDING A NEW DOCUMENT TO THE APPLICATION
oWordDoc = oWord.Documents.Open(file);
var templ = (Template) oWordDoc.get_AttachedTemplate();
var template = templ.FullName;
if (template.IndexOf(stringToFind) == -1)
{
continue;
}
var newTemplate = template.Replace(stringToFind, replaceWith);
oWordDoc.set_AttachedTemplate(newTemplate);
oWordDoc.SaveAs(file);
oWordDoc.Close();
fileInfo = new FileInfo(file);
fileInfo.LastWriteTime = modifyTime;
}
oWord.Quit();
Console.WriteLine("Done.");
Console.ReadLine();
}
}
}
This is a common issue with the Word interop: if the template location is not available then it's not possible to access this value. Word returns the template it can actually "reach" which by default will usually be Normal.dotm if the attached template cannot be found.
More reliable would be to work with the closed file via the Open XML SDK (it will be much faster, as well). Here's some code that will access the current information and change it. You will, of course, need to add the logic for which file is to be set as the new attached template.
string filePath = #"C:\Test\DocCopyTest.docm";
using (WordprocessingDocument pkgDoc = WordprocessingDocument.Open(filePath, true))
{
//Gets only the file name, not path; included for info purposes, only
DocumentFormat.OpenXml.ExtendedProperties.Template t = pkgDoc.ExtendedFilePropertiesPart.Properties.Template;
string tName = t.Text;
this.txtMessages.Text = tName;
//The attached template information is stored in the DocumentSettings part
//as a link to an external resource. So the information is not directly in the XML
//it's part of the "rels", meaning it has to be accessed indirectly
MainDocumentPart partMainDoc = pkgDoc.MainDocumentPart;
ExternalRelationship r = null;
string exRel_Id = "";
string exRelType = "";
//the file location of the new template, as a URI
Uri rUri = new Uri("file:////C:/Test/DocCopy_Test2.dotm");
Array exRels = partMainDoc.DocumentSettingsPart.ExternalRelationships.ToArray();
foreach (ExternalRelationship exRel in exRels)
if (exRel.RelationshipType.Contains("attachedTemplate"))
{
exRel_Id = exRel.Id;
exRelType = exRel.RelationshipType;
System.Diagnostics.Debug.Print(exRel_Id + " " + exRelType);
partMainDoc.DocumentSettingsPart.DeleteExternalRelationship(exRel);
r = partMainDoc.DocumentSettingsPart.AddExternalRelationship(exRelType, rUri, exRel_Id);
System.Diagnostics.Debug.Print(r.Uri.ToString());
break;
}
}

Pin *.lnk file to Windows 7 Taskbar using C#

Even the programmatic pinning of icons in Windows 7 seems it's not permitted (like it says here: http://msdn.microsoft.com/en-us/library/dd378460(v=VS.85).aspx), there are some methods for doing this by using some VB scripts.
Someone found a way of doing this in C# like this:
private static void PinUnpinTaskBar(string filePath, bool pin)
{
if (!File.Exists(filePath)) throw new FileNotFoundException(filePath);
// create the shell application object
dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
string path = Path.GetDirectoryName(filePath);
string fileName = Path.GetFileName(filePath);
dynamic directory = shellApplication.NameSpace(path);
dynamic link = directory.ParseName(fileName);
dynamic verbs = link.Verbs();
for (int i = 0; i < verbs.Count(); i++)
{
dynamic verb = verbs.Item(i);
string verbName = verb.Name.Replace(#"&", string.Empty).ToLower();
if ((pin && verbName.Equals("pin to taskbar")) || (!pin && verbName.Equals("unpin from taskbar")))
{
verb.DoIt();
}
}
shellApplication = null;
}
As can be seen, the code makes use of .NET Framework 4.0 features. The question I want to ask is: can this function be transformed so it would make the same thing, but using just 3.5 Framework? Any ideas?
Simple...
private static void PinUnpinTaskBar(string filePath, bool pin) {
if (!File.Exists(filePath)) throw new FileNotFoundException(filePath);
// create the shell application object
Shell shellApplication = new ShellClass();
string path = Path.GetDirectoryName(filePath);
string fileName = Path.GetFileName(filePath);
Folder directory = shellApplication.NameSpace(path);
FolderItem link = directory.ParseName(fileName);
FolderItemVerbs verbs = link.Verbs();
for (int i = 0; i < verbs.Count; i++) {
FolderItemVerb verb = verbs.Item(i);
string verbName = verb.Name.Replace(#"&", string.Empty).ToLower();
if ((pin && verbName.Equals("pin to taskbar")) || (!pin && verbName.Equals("unpin from taskbar"))) {
verb.DoIt();
}
}
shellApplication = null;
}
Be sure to add a COM reference to "Microsoft Shell Controls And Automation".
If you want to keep the existing method of using Activator.CreateInstance so you don't have to have the extra COM interop DLL then you'll have to use reflection. But that would make the code a lot uglier.
regardless what localization the Windows user was using:
int MAX_PATH = 255;
var actionIndex = pin ? 5386 : 5387; // 5386 is the DLL index for"Pin to Tas&kbar", ref. http://www.win7dll.info/shell32_dll.html
StringBuilder szPinToStartLocalized = new StringBuilder(MAX_PATH);
IntPtr hShell32 = LoadLibrary("Shell32.dll");
LoadString(hShell32, (uint)actionIndex, szPinToStartLocalized, MAX_PATH);
string localizedVerb = szPinToStartLocalized.ToString();
// create the shell application object
dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
string path = Path.GetDirectoryName(filePath);
string fileName = Path.GetFileName(filePath);
dynamic directory = shellApplication.NameSpace(path);
dynamic link = directory.ParseName(fileName);
dynamic verbs = link.Verbs();
for (int i = 0; i < verbs.Count(); i++)
{
dynamic verb = verbs.Item(i);
if ((pin && verb.Name.Equals(localizedVerb)) || (!pin && verb.Name.Equals(localizedVerb)))
{
verb.DoIt();
break;
}
}
In windows 10 the above methods don't work. The "Pin to Taskbar" verb doesn't appear in the list in your program, only in explorer. For this to work in windows 10, you have two options. Either rename you program to explorer.exe, or you have to fool the object in to thinking your program is called explorer.exe. You have to find the PEB and change the Image Path Field. I wrote a post here on how to do it.
Update for UWP apps running on Windows 10 with the Fall Creators Update (Build 16299 or higher):
You can programmatically pin your own app to the taskbar, just like you can pin your app to the Start menu. And you can check whether your app is currently pinned, and whether the taskbar allows pinning.
You can access the TaskbarManager API directly, as described in MS docs.
I wanted to do this with a WinForms application, but it does not seem like it is going to work because I cannot reference the Windows.Foundation APIs.

How can I programmatically open and save a PowerPoint presentation as HTML/JPEG in C# or Perl?

I am looking for a code snippet that does just this, preferably in C# or even Perl.
I hope this not a big task ;)
The following will open C:\presentation1.ppt and save the slides as C:\Presentation1\slide1.jpg etc.
If you need to get the interop assembly, it is available under 'Tools' in the Office install program, or you can download it from here (office 2003). You should be able to find the links for other versions from there if you have a newer version of office.
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
namespace PPInterop
{
class Program
{
static void Main(string[] args)
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
var file = pres.Open(#"C:\Presentation1.ppt", MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
file.SaveCopyAs(#"C:\presentation1.jpg", Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsJPG, MsoTriState.msoTrue);
}
}
}
Edit:
Sinan's version using export looks to be a bit better option since you can specify an output resolution. For C#, change the last line above to:
file.Export(#"C:\presentation1.jpg", "JPG", 1024, 768);
As Kev points out, don't use this on a web server. However, the following Perl script is perfectly fine for offline file conversion etc:
#!/usr/bin/perl
use strict;
use warnings;
use Win32::OLE;
use Win32::OLE::Const 'Microsoft PowerPoint';
$Win32::OLE::Warn = 3;
use File::Basename;
use File::Spec::Functions qw( catfile );
my $EXPORT_DIR = catfile $ENV{TEMP}, 'ppt';
my ($ppt) = #ARGV;
defined $ppt or do {
my $progname = fileparse $0;
warn "Usage: $progname output_filename\n";
exit 1;
};
my $app = get_powerpoint();
$app->{Visible} = 1;
my $presentation = $app->Presentations->Open($ppt);
die "Could not open '$ppt'\n" unless $presentation;
$presentation->Export(
catfile( $EXPORT_DIR, basename $ppt ),
'JPG',
1024,
768,
);
sub get_powerpoint {
my $app;
eval { $app = Win32::OLE->GetActiveObject('PowerPoint.Application') };
die "$#\n" if $#;
unless(defined $app) {
$app = Win32::OLE->new('PowerPoint.Application',
sub { $_[0]->Quit }
) or die sprintf(
"Cannot start PowerPoint: '%s'\n", Win32::OLE->LastError
);
}
return $app;
}

Categories