How to get file size in Dynamics AX / X++? - axapta

Does exists some Axapta method to get the size of a file ?
Thanks

You can use WinAPI function GetFileSize;
client public static int getFileSize(int hFile)
Example usage code is here;
http://msdn.microsoft.com/en-us/library/aa609747(v=ax.50).aspx
References;
http://msdn.microsoft.com/en-us/library/aa586314(v=ax.10).aspx

You can use the System.IO namespace too. For whatever reason, I don't have the getFileSize() in my AX instance available.
server static void main(Args args)
{
System.IO.FileInfo fi;
int64 length;
;
fi = new System.IO.FileInfo(#'C:\temp.csv');
length = fi.get_Length();
info(strfmt("%1", int642str(fi.get_Length())));
}

Related

How do I get ShellSettingsManager in an async extension to VS2019?

I wanted to create a small extension to add a list of External Tools to VS2019. A quick search brought up what appeared to be perfect example code at https://learn.microsoft.com/en-us/visualstudio/extensibility/writing-to-the-user-settings-store?view=vs-2019. This adds a command to invoke Notepad, so I thought with a few edits, my work was done.
However, this example is written as a synchronous extension, which is deprecated, so I tried putting the code intended for MenuItemCallBack into the Execute method of the extension, but the line
SettingsManager settingsManager = new ShellSettingsManager(ServiceProvider);
fails to compile, because ServiceProvider is now type IAsyncServiceProvider and the ShellSettingsManager constructor wants an argument of type IServiceProvider.
As far as I can tell, ShellSettingsManager is still the way to access the Settings Store, but all the examples I could find all refer to putting code in MenuItemCallback (as well as being several years old) so are for synchronous extensions.
So, can someone point me to the recommended way to get access to the settings store in an asynchronous extension?
The ShellSettingsManager constructor takes either an IServiceProvider interface or an IVsSettings interface. Given your AsyncPackage derived object implements IServiceProvider, you should be able to just pass it in as the argument to your constructor. The following quick demo package worked for me:
using System;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft;
using Microsoft.VisualStudio.Settings;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.Settings;
using Task = System.Threading.Tasks.Task;
namespace UserSettingsDemo
{
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
[Guid(UserSettingsDemoPackage.PackageGuidString)]
[ProvideMenuResource("Menus.ctmenu", 1)]
public sealed class UserSettingsDemoPackage : AsyncPackage
{
public const string PackageGuidString = "cff6cdea-21d1-4736-b5ea-6736624e718f";
public static readonly Guid CommandSet = new Guid("dde1417d-ae0d-46c4-8c84-31883dc1a835");
public const int ListExternalToolsCommand = 0x0100;
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
{
await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
OleMenuCommandService commandService = await GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
Assumes.Present(commandService);
var menuItem = new MenuCommand(OnListExternalTools, new CommandID(CommandSet, ListExternalToolsCommand));
commandService.AddCommand(menuItem);
}
private void OnListExternalTools(object sender, EventArgs e)
{
ShellSettingsManager settingsManager = new ShellSettingsManager(this);
WritableSettingsStore userSettingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
int toolCount = userSettingsStore.GetInt32("External Tools", "ToolNumKeys");
for (int i = 0; i < toolCount; i++)
{
string tool = userSettingsStore.GetString("External Tools", "ToolCmd" + i);
VsShellUtilities.ShowMessageBox(this, tool, "External Tools", OLEMSGICON.OLEMSGICON_INFO,
OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
}
}
}
}
Sincerely

flyway - The meaning of the concept of checksums

I'm learning Flyway migration tool, and I don't have clear the concept of checksums. Could someone explain me what is? how is it calculated, or how can it be changed?
I understand the repair command re-calculate the checksum, I do not understand how it differs.
Thanks!
Checksum field in Flyway forming a part of verification mechanism ensuring that migration scripts haven't been changed since they applied to the database. This will guaranty that all instances of your application will have same database structure (content). You can switch off verification, but I will not recommend you to do so. Answering you questions:
What is?
Just google what is checksum. Wikipedia
How is it calculated?
For SQL migrations Flyway uses CRC32 class to calculate the checksum. For exact code see below.
How can it be changed?
The checksum of the migration will be changed once the binary content of you migration modified. If you want to change checksum field in the DB when you need to calculate the checksum for the new version of your migration file and then change the value in the DB. However, I wouldn't recommend to do that. You shouldn't need to do that and the fact that you want to change it may indicate that you doing something wrong. Anyway, the calculation code for the checksum is quite simple (with courtesy of Flyway source code):
/**
* Calculates the checksum of this string.
*
* #param str The string to calculate the checksum for.
* #return The crc-32 checksum of the bytes.
*/
/* private -> for testing */
static int calculateChecksum(Resource resource, String str) {
final CRC32 crc32 = new CRC32();
BufferedReader bufferedReader = new BufferedReader(new StringReader(str));
try {
String line;
while ((line = bufferedReader.readLine()) != null) {
crc32.update(line.getBytes("UTF-8"));
}
} catch (IOException e) {
String message = "Unable to calculate checksum";
if (resource != null) {
message += " for " + resource.getLocation() + " (" + resource.getLocationOnDisk() + ")";
}
throw new FlywayException(message, e);
}
return (int) crc32.getValue();
}
To calculate flyway checksum for arbitrary file, I use the following code:
import java.util.*;
import org.flywaydb.core.internal.resource.filesystem.*;
import org.flywaydb.core.internal.resolver.*;
import java.nio.charset.*;
public class Program {
public static void main( String[] args ) throws Exception{
String filename="/path/to/migration/V8_test.sql";
FileSystemResource r = new FileSystemResource(null, filename,Charset.forName("UTF-8"));
int cs = ChecksumCalculator.calculate(r);
System.out.println(cs);
}
}
Only dependency for this code is org.flywaydb:flyway-core:6.4.1
For version 8.10 #Eugene's answer needs to change a bit:
get_flyway_checksum.java:
import java.util.*;
import org.flywaydb.core.internal.resource.filesystem.*;
import org.flywaydb.core.internal.resolver.*;
import org.flywaydb.core.internal.resource.*;
import org.flywaydb.core.api.Location;
import java.nio.charset.*;
public class Program {
public static void main( String[] args ) throws Exception{
Location loc = null;
String filepath = args[0];
FileSystemResource r = new FileSystemResource(loc, filepath,Charset.forName("UTF-8"), false);
int cs = ChecksumCalculator.calculate(r);
System.out.println(cs);
}
}
To get the checksum:
java -cp {path to your flyway installation}/lib/community/flyway-core-8.1.0.jar get_flyway_checksum.java {filepath}

log4cxx -- is it possible to configure a custom appender with custom arguments from a config file?

I need to write a custom appender in log4cxx. This answer describes how to do it. In Java, in log4j, it is possible for a custom appender to devise custom parameters. I add a property and a getter and setter:
private int myParameter = 0;
public void setMyParameter(int p) { myParameter = p; }
public int getMyParameter() { return myParameter; }
Then I can use myParameter in configuration file, and the framework somehow knows how to configure my appender with it.
Question: does log4cxx have a similar capability? For me it is enough if I get a map map<string, string> with properties.
Ok, figured out the answer myself. You need to override member function setOption. It will get called a number of times: once per each read option. You then override function activateOptions and its get called after all options have been processed. It can be used as a trigger to initialize the appender with the read parameters.
Not as convenient as mapping to getters/setters, but it gets the job done:
class CustomAppender : public AppenderSkeleton
{
int _myParameter = 0;
void initialize(int myParameter);
// ...
public:
void setOption(LogString const& option, LogString const& value) override
{
if (option == "MyParameter") try
{
_myParameter = boost::lexical_cast<int>(value);
}
catch (boost::bad_lexical_cast const&) {
// go with default
}
}
void activateOptions(helpers::Pool &) override
{
initialize(_myParameter);
}
};

Create path from path value?

Can i create a Path using its value??
Path p=new Path();
p.getElements().add(new MoveTo(mouse.getX(), mouse.getY()));
System.out.Print(p);
This will print
Path#29f12030
can i convert this into path again?
You have already created a path and it's still a path, you don't need to convert it.
When you call System.out.print(p) you invoke the default toString function on your p object, which prints an internal Java reference to your Path (e.g. Path#29f12030).
If you override the default toString method with your own implementation, as is shown in the sample below, your print statement will display the value of the path.
public class PrintPath extends Application {
public static void main(String[] args) throws Exception { launch(args); }
#Override public void start(final Stage stage) throws Exception {
Path p = new PrintedPath();
p.getElements().add(new MoveTo(100, 150));
System.out.println(p);
stage.setScene(new Scene(new StackPane()));
stage.show();
}
class PrintedPath extends Path {
#Override public String toString() {
StringBuilder b = new StringBuilder();
for (PathElement e: getElements()) {
if (e instanceof MoveTo) {
MoveTo m = (MoveTo) e;
b.append("M").append(m.getX()).append(" ").append(m.getY()).append(" ");
}
// logic to display other path element types could be added here . . .
}
return "Path{ " + b.toString() + "}";
}
}
}
I think you should elaborate your purpose of sending data over network in a context of your app architecture. Give some fundamental details about it. In my understanding, you want to send a Path instance over the network and able to process it on the other end. If so,
- have a look to a serialization API. Read the post about it "How to transfer objects over network using java". Extend the Path or wrap it into another class then implement Serializable.
- Or, refer to Java Architecture for XML Binding (JAXB). Basically by using it you can convert/marshal the objects to XML strings and transfer over the network and then unmarshal it. Here is hello world example.
- Or, implement your own encoding/decoding mechanism to transfer the Path object.

How to Track Queries on a Linq-to-sql DataContext

In the herding code podcast 14 someone mentions that stackoverflow displayed the queries that were executed during a request at the bottom of the page.
It sounds like an excellent idea to me. Every time a page loads I want to know what sql statements are executed and also a count of the total number of DB round trips.
Does anyone have a neat solution to this problem?
What do you think is an acceptable number of queries? I was thinking that during development I might have my application throw an exception if more than 30 queries are required to render a page.
EDIT: I think I must not have explained my question clearly. During a HTTP request a web application might execute a dozen or more sql statements. I want to have those statements appended to the bottom of the page, along with a count of the number of statements.
HERE IS MY SOLUTION:
I created a TextWriter class that the DataContext can write to:
public class Logger : StreamWriter
{
public string Buffer { get; private set; }
public int QueryCounter { get; private set; }
public Logger() : base(new MemoryStream())
{}
public override void Write(string value)
{
Buffer += value + "<br/><br/>";
if (!value.StartsWith("--")) QueryCounter++;
}
public override void WriteLine(string value)
{
Buffer += value + "<br/><br/>";
if (!value.StartsWith("--")) QueryCounter++;
}
}
In the DataContext's constructor I setup the logger:
public HeraldDBDataContext()
: base(ConfigurationManager.ConnectionStrings["Herald"].ConnectionString, mappingSource)
{
Log = new Logger();
}
Finally, I use the Application_OnEndRequest event to add the results to the bottom of the page:
protected void Application_OnEndRequest(Object sender, EventArgs e)
{
Logger logger = DataContextFactory.Context.Log as Logger;
Response.Write("Query count : " + logger.QueryCounter);
Response.Write("<br/><br/>");
Response.Write(logger.Buffer);
}
If you put .ToString() to a var query variable you get the sql. You can laso use this in Debug en VS2008. Debug Visualizer
ex:
var query = from p in db.Table
select p;
MessageBox.SHow(query.ToString());
System.IO.StreamWriter httpResponseStreamWriter =
new StreamWriter(HttpContext.Current.Response.OutputStream);
dataContext.Log = httpResponseStreamWriter;
Stick that in your page and you'll get the SQL dumped out on the page. Obviously, I'd wrap that in a little method that you can enable/disable.
I have a post on my blog that covers sending to log files, memory, the debug window or multiple writers.
From Linq in Action
Microsoft has a Query Visualizer tool that can be downloaded separetly from VS 2008. it is at http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx

Resources