Your message has been sent.
This article has been saved to your account.
Go to my account
This article has been emailed to your Kindle.
Send this article
Complete the form below to send this article, Microsoft Dynamics NAV: OS Integration, to a friend (or to yourself). We will never share your details (or your friend's) with anyone. For more information, read our Privacy Policy.
In this article by Matt Traxinger, author of Microsoft Dynamics NAV 2009 Programming Cookbook, we will cover:
- Using HYPERLINK to open external files
- Working with environment variables
- Using SHELL to run external applications
- Browsing for a file
- Browsing for a folder
- Checking file and folder access permissions
- Querying the registry
- Zipping folders and files within NAV
| Read more about this book |
Introduction
If you have programmed with Windows or used a Windows-based operating system for any length of time you will see that it is really an all-encompassing OS, at least for our needs. Unlike with other types of software development, we don't need to interact with device drivers or create three dimensional graphics for our users. Most of what we need to do involves integrating with the file system; that is searching for files or folders and running external applications.
Occasionally, we may need to go a little deeper. There may be instances where we need to check the user's environment, query the registry, or check for specific administrator permissions. These can all be performed within NAV, although many require a little outside help from a built-in or custom automation control.
As Windows is such a large piece of software, it already contains ways for us to do these things. As a result, the recipes in this article are not very lengthy or complicated, but that does not make them any less useful. They explore the basics of what you can do with the OS and it is up to you to decide when and how to make the best use of them.
It is important to note that many of these recipes will require additional coding to make them work with the RoleTailored client. This is because the code is actually executing on a server, not your own computer as it does with the Classic client.
Using HYPERLINK to open external files
Many times you may need to open files external to the NAV program. NAV has a built-in function that interacts with the file system to open the file with the appropriate application.
How to do it...
- Create a new codeunit from Object Designer.
- Add the following global variable:
Name Type Selection Integer - Add the following code to the OnRun trigger:
Selection := STRMENU('Image,Website');
IF Selection = 1 THEN
HYPERLINK('C:\Users\Public\
Pictures\Sample Pictures\Penguins.jpg')
ELSE
HYPERLINK('HTTP://www.mibuso.com'); - Save and close the codeunit.
How it works...
When you run the codeunit you will be presented with a simple selection menu that asks you to choose between an image and a website. Depending on your choice we will use the HYPERLINK command to load a specific file. This command takes in a single string which points to a location and loads that pointer using the default program on the current machine.
If you choose Image then the Penguins image that ships with Microsoft Windows 7 will load in the default program you have set to open pictures, usually Windows Photo Viewer.

If you choose Website then the Mibuso website will open in your default internet browser, typically Internet Explorer.
There's more...
With the RoleTailored client, it is best to use HYPERLINK with shared drives and folders. This is because the actual HYPERLINK command is running on the NAV service tier, not on the local computer or client. It has no idea about the user's system. This example is for the Classic client (thus the link to a file on the C: drive), but changing the parameter to a shared file on your network should work just fine.
See also
- Using SHELL to run external applications
- Browsing for a file
- Checking file and folder access permissions
Working with environment variables
Environment variables are a set of named values that can affect the way processes and applications run on a computer. NAV has a built-in function to reference these variables and lets you change the way it functions.
How to do it...
- Create a new codeunit from Object Designer.
- Add the following code to the OnRun trigger:
MESSAGE(' OS: %1\Temp: %2\WinDir: %3', ENVIRON('OS'),
ENVIRON('TEMP'), ENVIRON('WINDIR')); - Save and close the codeunit.
How it works...
The ENVIRON function takes in a single string and returns a string. Our codeunit uses the ENVIRON function to return three common environment variables: the name of the operating system, the path to the temporary folder for the current user, and the path to the Windows installation directory.
In Windows 7, in order to see all of the options available to the ENVIRON command, simply right-click on My Computer and go to Properties.

Click on Advanced system settings, the Advanced tab, and then on the Environment Variables button. You will find them in the System variables section of the window.

There's more...
This recipe is not compatible with the RoleTailored client. The code running on the NAV service tier does not know anything about the client operating system. There is, however, a way around this. We need a way to force code to be executed on the client-side instead of the server-side.
ENVIRON for the RoleTailored client
We can force our code to execute on the client-side by creating an Automation. Start by creating a new project in Visual Studio with the following code:
using System.Management;
using System.Runtime.InteropServices;namespace RemoteSystemInfo
{
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("RemoteSystemInfo")]
[ComVisible(true)]
public class RemoteSystemInfo
{
public string GetSysInfo(string domain, string machine,
string username, string password, string variable)
{
ManagementObjectSearcher query = null;
ManagementObjectCollection queryCollection = null;
ConnectionOptions opt = new ConnectionOptions();
opt.Impersonation = ImpersonationLevel.Impersonate;
opt.EnablePrivileges = true;
opt.Username = username;
opt.Password = password;try
{
ManagementPath p = new ManagementPath(@"\\" +
machine + @"\root\cimv2");
ManagementScope msc = new ManagementScope(p, opt);
SelectQuery q = new SelectQuery("Win32_Environment");
query = new ManagementObjectSearcher(msc, q, null);
queryCollection = query.Get();foreach (ManagementBaseObject envVar in queryCollection)
{
if (envVar["Name"].ToString() == variable)
{
return envVar["VariableValue"].ToString();
}
}
}
catch (ManagementException e)
{
throw new ManagementException("Management Exception:
" + e.Message);
}
catch (System.UnauthorizedAccessException e)
{
throw new ManagementException("Access Exception:
" + e.Message);
}
return "";
}
}
}
When using the Automation in your NAV objects you must do the following:
CREATE(MyAutomation, FALSE, TRUE);
The third parameter tells the system to create the instance of the Automation on the client (TRUE) and not the server (FALSE). As the code executes on the client machine it can query the environment variables and easily return the correct result. Just pass the appropriate values to the GetSysInfo function.
See also
- Using SHELL
Using SHELL to run external applications
Just as external files can be opened from within NAV, so can external programs. This recipe will show you how to launch one of such applications.
How to do it...
- Create a new codeunit from Object Designer.
- Add the following code to the OnRun trigger:
SHELL(ENVIRON('WINDIR') + '\notepad.exe');
- Save and close the codeunit.
How it works...
The SHELL command takes in a required string parameter representing the application to launch. There is an optional second parameter that will be passed as an argument to the application to be launched (not used here). This argument could represent a file to open or other flags incorporated into the program.
See also
- Querying the registry
| Read more about this book |
Browsing for a file
You will perform many modifications that require input from a file on the Windows file system. Instead of requiring the user to remember the full path and name of the file, we will show you how to use an out-of-the-box codeunit to let them select the file using a dialog box.
How to do it...
- Create a new codeunit from Object Designer.
- Add the following global variables:
Name Type Subtype Length CommonDialogMgt Codeunit Common Dialog Management SelectedFile Text 255 - Add the following code to the OnRun trigger:
SelectedFile := CommonDialogMgt.OpenFile('NAV File Browser',
SelectedFile,1,'Filter',0);
MESSAGE('You selected %1', SelectedFile); - Save and close the codeunit.
How it works...
NAV provides a codeunit, number 412, named Common Dialog Management. It uses an OCX that references to the Microsoft Common Dialog Control. This codeunit provides a function that allows you to open a simple dialog box in either Open or Save mode. This function, OpenFile, takes five parameters.
The first is the title of the dialog box or Window. Next is the default file name to look for. The third and fourth parameters work together. The third is the default file type. When this is set to Custom the function uses the filter string passed in parameter four. The final argument tells the dialog box which mode to open in, that is Open or Save.

Should you choose to open the dialog box with a custom file type, you will have to enter a filter. You can see how these filters are formed by examining the global text constants, but we have also provided an example here:
Text Files (*.txt)| *.txt | All Files (*.*) | *.*
See also
- Using HYPERLINK to open external files
- Checking file and folder access permissions
- Browsing for a folder
Browsing for a folder
NAV provides us with a way to browse for a file right out-of-the-box, but it does not let us browse for a folder. This recipe will show you a work around using automation controls that should already be installed on your system.
How to do it...
- Create a new codeunit from Object Designer.
- Add the following global variables:
Name Type Subtype Length MSShell Automation 'Microsoft Shell Controls And Automation'.Shell Folder Automation 'Microsoft Shell Controls And Automation'.Folder3 FilesInFolder Automation 'Microsoft Shell Controls And Automation'. FolderItems3 CurrentFile Automation 'Microsoft Shell Controls And Automation'. FolderItem2 SelectedFolder Text 1024 - Add the following code to the OnRun trigger:
CREATE(MSShell, FALSE, TRUE);
Folder := MSShell.BrowseForFolder(0, 'NAV Folder Browser', 0);
FilesInFolder := Folder.Items();
CurrentFile := FilesInFolder.Item();
SelectedFolder := FORMAT(CurrentFile.Path);
MESSAGE('Selected Folder: %1\Contains %2 files',
SelectedFolder, FilesInFolder.Count()); - Save and close the codeunit.
How it works...
This recipe depends entirely on the classes found in the Microsoft Shell Controls and Automation package.
For a list of the objects found in this package you can search MSDN or go to
http://msdn.microsoft.com/en-us/library/bb776890%28VS.85%29.aspx.
The code may seem like a lot just to get a folder name, but let's go through it line-by-line and explain why we are doing what we are doing. First we create or instantiate our MSShell variable, just as we do with every Automation variable. This one has a function called BrowseForFolder that launches the dialog box.

Unfortunately, this function returns a Folder object, which does not have text representation. So we have to take it a step further. We then retrieve a list of the files contained in that folder. This list is stored in our FilesInFolder variable. We can access the first item in this list. This file has a path and we can store that as our selected folder.
See also
- Browsing for a file
- Checking file and folder access permissions
Checking file and folder access permissions
Many systems have batch processes which read and write files to folders on the file system. In order to avoid some of the standard Windows error messages and prevent errors in the middle of the process you may want to check access permissions.
How to do it...
- Create a new Class Library project in Visual Studio.
- Create a new file with the following code:
using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
namespace FolderAccess
{
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("RegistryQuery")]
[ComVisible(true)]
public class FolderAccess
{
public bool TestFolderAccess(string folder, string access)
{
System.Security.Permissions.FileIOPermissionAccess
accessLevel;
switch (access.ToUpper())
{
case "NOACCESS": accessLevel =
FileIOPermissionAccess.NoAccess; break;
case "READ": accessLevel =
FileIOPermissionAccess.Read; break;
case "WRITE": accessLevel =
FileIOPermissionAccess.Write; break;
case "APPEND": accessLevel =
FileIOPermissionAccess.Append; break;
case "PATHDISCOVERY": accessLevel =
FileIOPermissionAccess.PathDiscovery; break;
case "ALLACCESS": accessLevel =
FileIOPermissionAccess.AllAccess; break;
default: return false;
}
FileIOPermission permission = new
FileIOPermission(accessLevel, folder);
try
{
permission.Demand();
}
catch (Exception ex)
{
return false;
}
return true;
}
}
} - Save, compile, and close the project.
- Create a new codeunit from Object Designer.
- Add the following global variable:
Name Type Subtype FolderAccess Automation 'FolderAccess'.FolderAccess - Add the following code to the OnRun trigger:
CREATE(FolderAccess, FALSE, TRUE);
MESSAGE('Access: %1',
FolderAccess.TestFolderAccess('C:\', 'WRITE')); - Save and close the codeunit.
How it works...
Our custom C# function, TestFolderAccess, takes in two parameters: the path or folder to check and the type of permission to check for. Using the FileIOPermission class we set these values and demand the access level. The Demand function will throw an exception if we do not currently have access to the folder. In that case we return false, but in all other cases we return true.
See also
- Browsing for a file
- Browsing for a folder
Querying the registry
You may never need to query the registry on the computer when creating a NAV modification, but you should consider it as an option.
How to do it...
- Create a new Class Library project in Visual Studio.
- Create a new file with the following code:
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace RegistryQuery
{
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("RegistryQuery")]
[ComVisible(true)]
public class RegistryQuery
{
public string GetKeyValue(string key, string name)
{
RegistryKey regKey = Registry.Users.OpenSubKey(key);
if (regKey == null)
{
return "Key not found!";
}
else
{
object value = regKey.GetValue(name);
if (value != null)
{
return value.ToString();
}
else
{
return "Name not found!";
}
}
}
}
} - Save, compile, and close the project.
- Create a new codeunit from Object Designer.
- Add the following global variable:
Name Type Subtype RegistryQuery Automation 'RegistryQuery'.RegistryQuery - Add the following code to the OnRun trigger:
CREATE(RegistryQuery, FALSE, TRUE);
MESSAGE('%1', RegistryQuery.GetKeyValue('.DEFAULT\Environment',
'TEMP')); - Save and close the codeunit.
How it works...
You may never have an instance where you need to examine registry values in your NAV code. In most instances, it will be easier to add a column to User Setup or store the information in a custom table. As a NAV developer, and less specifically, a business applications developer, you may encounter a situation that warrants this type of development. Let's take a look at the code.
Our C# code works for a specific root in the registry, HKEY_USERS. We access the subkey passed in the first parameter to our function using the Registry.Users.OpenSubKey function. If the key is not found, or null, we return an appropriate message. You could modify the code to access the other root folders by passing an additional parameter.
Next, we try to access the names stored in the key. Again, if we are unable to find the key equal to the second parameter of our function, we return null. If we do find it, we return its value.

Our NAV code looks for the temporary folder assigned to the user, similar to what ENVIRON('TEMP') returns. Do not think that this is only limited to things that can also be found using the ENVIRON function, though. You can query any value in the registry.
There's more...
You can also perform other actions on the registry using the CreateSubKey and DeleteSubKey functions. Be warned, though. You should not play with the registry unless you know what you are doing. You can easily corrupt the entire system if you are not careful.
For more information about the registry you can view this MSDN article:
http://msdn.microsoft.com/en-us/library/h5e7chcf.aspx
See also
- Working with environment variables
Zipping folders and files within NAV
This might not be a common task, but creating files and e-mailing them from within NAV is. You can combine this with those recipes to send large groups of files at once.
How to do it...
- Create a new codeunit from Object Designer.
- Add the following global variables:
Name Type Subtype ZipFile File MSShell Automation 'Microsoft Shell Controls And Automation'.Shell
ZipFolder Automation 'Microsoft Shell Controls And Automation'.Folder - Add the following code to the OnRun trigger:
ZipFile.CREATE(
'C:\Users\Public\Pictures\Sample Pictures\Pictures.zip');
CREATE(MSShell, FALSE, TRUE);
ZipFolder := MSShell.NameSpace(
'C:\Users\Public\Pictures\Sample Pictures\Pictures.zip');
ZipFolder.CopyHere(
'C:\Users\Public\Pictures\Sample Pictures\Desert.jpg'); - Save and close the codeunit.
How it works...
A ZIP file is really just a folder that happens to have its contents compressed. We can create this file or folder just as we would create a text file, using the CREATE command.
Next, we assign the namespace of our MSShell object to this ZIP file. This means that whatever we do with our MSShell variable we will be doing to this file.
As the ZIP file is really just a folder, we can perform any file system action on it. In this case, we want to copy files into the folder. We achieve this by using the CopyHere function where the "Here" refers to our namespace and the parameter passed tells the function which file to copy.
Summary
In this article we covered the following recipes:
- Using HYPERLINK to open external files
- Working with environment variables
- Using SHELL to run external applications
- Browsing for a file
- Browsing for a folder
- Checking file and folder access permissions
- Querying the registry
- Zipping folders and files within NAV
About the Author :
Matt Traxinger
Matt Traxinger graduated from the Georgia Institute of Technology in 2005 with a B.S. in Computer Science, specializing in Human Computer Interaction and Cognitive Science. After college he took a job as an add-on developer using a language he was unfamiliar with for a product he had never heard of: Navision. It turned out to be a great decision.
In the years following Matt learned all areas of the product and earned Microsoft Certified Business Solutions Professional certifications in both technical and functional areas of NAV. He continues to stay current with new releases of the product and is certified in multiple areas for versions 4.0, 5.0, and 2009.
Currently Matt works in Norcross, GA, for Canvas Systems, one of the largest resellers of new and refurbished computer equipment as an in-house NAV Developer and Business Analyst. He supports multiple offices in the United States as well as locations in the United Kingdom and the Netherlands.
In his spare time you can find him on the online communities Mibuso.com and DynamicsUser.net under the name MattTrax, helping others learn more about the Dynamics NAV software.
Books From Packt
|
|
|



Post new comment