Обязан­ности:

  • Разра­ботка стратегии и плани­ро­вание продви­жения программных продуктов(deskctop и mobile)
  • Внедрение стратегии, плани­ро­вание, работа по плану
  • Такти­ческое управ­ление продуктом: тарифы, акции, стиму­ли­ро­вание роста продаж и доходов
  • Разра­ботка сопут­ствующих докумен­таций, презен­таций, флайеров(текст, без дизайна)
  • Прозрач­ность работы, отчетность

Требо­вания:

  • Опыт работы в марке­тинге или управ­лении проектами от 2 лет
  • Хороший разго­ворный и письменный английский язык, опцио­нально немецкий
  • Знание инстру­ментов интернет-маркетинга
  • Умение грамотно поставить задачу группе програм­мистов, SEO writers
  • Личные качества: анали­ти­ческие способ­ности, умение работать самосто­я­тельно и в команде, креатив­ность, нацелен­ность на высокий результат

Условия:

  • Преми­ро­вание при выпол­нении плана
  • % от продаж
 

Тип занятости:

  • Удалённая работа
  • Полная занятость, полный день
  • Коман­ди­ровки в Германию, Мюнхен.
  • Участие в между­на­родных выставках
10 Ноября

В августе 2009 мы выиграли тендер на обслу­жи­вание проекта “Pflege und Weiterentwicklung Textsystem_RP” министерства юстиции Rheinland-Pfalz. И уже в ноябре 2009 получили право на работу с этим проектом.

Наша фирма учавствует в между­на­родной выставке “Связь, Инфор­мация. IT-Техно­логии 2013” в Екатеринбурге.

Приме­нение JNA (Java Native Access) в Java-проектах для доступа к функци­о­наль­ности и объектам, так называемых «нативных» библиотек — COM-DLL Microsoft Windows, представляет собой большой интерес.
Основным преиму­ще­ством является сокра­щение времени разра­ботки проекта, если вся необхо­димая функци­о­наль­ность уже содер­жится в какой-то стандартной библиотеке Microsoft Windows, либо есть сторонняя COM-DLL с необхо­димым набором решений, либо это уже приме­няемая клиентом COM-DLL бизнес-логики. Также невоз­можно переоценить возмож­ность исполь­зо­вания COM-DLL, работающей с объектами Microsoft .NET Framework, написанная, например, на C#.
Вторым, но не меньшим по значи­мости преиму­ще­ством является то, что в отличие от преды­дущей техно­логии JNI (Java Native Interface), здесь не придется писать библиотеку-оболочку на C, а это и в правду сомни­тельное удовольствие.
Но обо всем по порядку. Рассмотрим задачу, которая и подвигла на изучение техно­логии JNA.
Для нужд проекта потре­бо­валось получить список принтеров в системе, но также название их драйверов, т.к. имя принтера можно задать вручную какое угодно, хоть «MySuperPuperPrinter», а проекту требо­валось что-то более надежное и стабильное. Результат решения, которое предлагает Java, оказался неправильным…
Восполь­зуемся библио­текой javax.print:

import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.standard.PrinterMakeAndModel;
 
public class Tester {
    public static void main(String[] args) {
        final PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
        for (PrintService printService : printServices) {
            System.out.println("PrinterName = " + printService.getName() +
                    ", PrinterMakeAndModel = " + printService.getAttribute(PrinterMakeAndModel.class));
        }
    }
}

Моя система показывает следующий результат:
PrinterName = Samsung SCX-4x28 Series PCL6, PrinterMakeAndModel = null
PrinterName = Samsung CLX-3180 Series, PrinterMakeAndModel = null
PrinterName = PDF Creator, PrinterMakeAndModel = null
PrinterName = FinePrint, PrinterMakeAndModel = null
PrinterName = Fax, PrinterMakeAndModel = null

Где инфор­мация о драйвере или модели принтера? Ее нет.
Посмотрим, что говорит об этом Oracle:

For attributes like
javax.print.attribute.standard.PrinterMakeAndModel
javax.print.attribute.standard.PrinterLocation
javax.print.attribute.standard.PrinterInfo
javax.print.PrintService.getAttribute should return meaningful information obtained from the Windows OS, instead of empty strings.
This bug can be reproduced always.
EVALUATION 2003-02-18
In Windows, this information can be retrieved from PRINTER_INFO_X structure.

ОК, проверим последнюю версию Java 1.7.0_17 – результат тот же, т.е. проблема 2003 не исправлена.

Ну да ладно, в принципе Java не предна­значена знать все тонкости опера­ци­онной системы, на которой она работает. Поэтому, как там Microsoft Windows разби­рается со своими принтерами, должен был бы знать какой-нибудь Microsoft Windows сервис. Он есть – это библиотека c:WindowsSystem32Winspool.drv и ее функция EnumPrinters. Функция перечисляет принтеры системы и складывает инфор­мацию как раз в структуру PRINTER_INFO_2.

Чтобы получить доступ к библиотеке Winspool.drv можно исполь­зовать JNI – для этого нам придется писать оболочку на С, h‑файл со стороны JNI и т.д. Для неспе­ци­а­листа в этой техно­логии доста­точно трудо­емкий и время затратный процесс, а уж о трудностях отладки я вообще молчу.

Посмотрим, что нам может предложить JNA.

Начнем с самого ориги­нального примера «Hello World», что мне прихо­дилось видеть, от разра­ботчика JNA.

import com.sun.jna.Library;
import com.sun.jna.Native;
public class Tester {
    public interface Kernel32 extends Library {
        boolean Beep(int frequency, int duration);
    }
    private static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
    private static void toMorseCode(String letter) throws Exception {
        for (byte b : letter.getBytes()) {
            kernel32.Beep(1200, ((b == '.') ? 50 : 150));
            Thread.sleep(50);
        }
    }
    public static void main(String[] args) throws Exception {
        String helloWorld[][] = {
                {"....", ".", ".-..", ".-..", "---"}, // HELLO
                {".--", "---", ".-.", ".-..", "-.."}  // WORLD
        };
        for (String word[] : helloWorld) {
            for (String letter : word) {
                toMorseCode(letter);
                Thread.sleep(150);
            }
            Thread.sleep(350);
        }
    }
}

Т.е. доста­точно объявить интерфейс, расши­ряющий com.sun.jna.Library, объявить в нем необхо­димый метод с именем и сигна­турой, соответ­ству­ющими функции из библиотеки (в данном случае это библиотека c:WindowsSystem32kernel32.dll и функция Beep), и загрузить библиотеку, используя этот интерфейс с помощью com.sun.jna.Native. Первым параметром выступает имя библиотеки, которое может содержать полный путь к ней в файловой системе, а вторым – класс интер­фейса, который исполь­зуется для связы­вания интер­фейса и библиотеки посред­ством reflection.

Впечатляет, насколько просто можно услышать привет­ствие компьютера «Hello World», которое он проби­бикает азбукой Морзе.

Также интересные примеры можно найти тут.

Теперь вернемся к задаче проекта – получить имена принтеров и их драйверов в Microsoft Windows. Как было сказано выше, нужно обратиться к Winspool.drv и посред­ством ее функции EnumPrinters получить набор структуры PRINTER_INFO_2 для каждого принтера в системе. К счастью JNA позабо­тился об обертке структур «нативных» библиотек и предо­ставила класс com.sun.jna.Structure.

Тестовый код выглядит так:

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import java.util.Arrays;
import java.util.List;
 
public class WinSpoolTest {
     
    public interface Winspool extends StdCallLibrary {
         
        boolean EnumPrinters(int flags, String name, int level, Pointer pPrinterEnum, int cbBuf, IntByReference pcbNeeded, IntByReference pcReturned);
        public static final int PRINTER_ENUM_LOCAL = 0x00000002;
        public static final int LEVEL2 = 2;
         
        public static class PRINTER_INFO_2 extends Structure {
            public String pServerName;
            public String pPrinterName;
            public String pShareName;
            public String pPortName;
            public String pDriverName;
            public String pComment;
            public String pLocation;
            public WinDef.INT_PTR pDevMode;
            public String pSepFile;
            public String pPrintProcessor;
            public String pDatatype;
            public String pParameters;
            public WinDef.INT_PTR pSecurityDescriptor;
            public int Attributes;
            public int Priority;
            public int DefaultPriority;
            public int StartTime;
            public int UntilTime;
            public int Status;
            public int cJobs;
            public int AveragePPM;
             
            @Override
            protected List<String> getFieldOrder() {
                return Arrays.asList(
                        "pServerName",
                        "pPrinterName",
                        "pShareName",
                        "pPortName",
                        "pDriverName",
                        "pComment",
                        "pLocation",
                        "pDevMode",
                        "pSepFile",
                        "pPrintProcessor",
                        "pDatatype",
                        "pParameters",
                        "pSecurityDescriptor",
                        "Attributes",
                        "Priority",
                        "DefaultPriority",
                        "StartTime",
                        "UntilTime",
                        "Status",
                        "cJobs",
                        "AveragePPM");
            }
            public PRINTER_INFO_2() {
            }
             
            public PRINTER_INFO_2(int size) {
                super(new Memory(size));
            }
        }
    }
     
    final static Winspool winspool = (Winspool) Native.loadLibrary("Winspool.drv", Winspool.class, W32APIOptions.UNICODE_OPTIONS);
     
    public static void main(String[] args) throws Exception {
        final IntByReference pcbNeeded = new IntByReference();
        final IntByReference pcReturned = new IntByReference();
        winspool.EnumPrinters(Winspool.PRINTER_ENUM_LOCAL, null, Winspool.LEVEL2, null, 0, pcbNeeded, pcReturned);
        if (pcbNeeded.getValue() <= 0) {
            return;
        }
        final Winspool.PRINTER_INFO_2 pPrinterEnum = new Winspool.PRINTER_INFO_2(pcbNeeded.getValue());
        if (!winspool.EnumPrinters(Winspool.PRINTER_ENUM_LOCAL, null, Winspool.LEVEL2, pPrinterEnum.getPointer(),
                pcbNeeded.getValue(), pcbNeeded, pcReturned)) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
        pPrinterEnum.read();
        final Winspool.PRINTER_INFO_2[] result = (Winspool.PRINTER_INFO_2[]) pPrinterEnum.toArray(pcReturned.getValue());
        for (Winspool.PRINTER_INFO_2 pi : result) {
            System.out.printf("PrinterName = %1$2s, DriverName = %2$2sn", pi.pPrinterName, pi.pDriverName);
        }
    }
}

Что мы видим тут? Интерфейс Winspool теперь расширяет StdCallLibrary, а также содержит структуру PRINTER_INFO_2, наследницу Structure. Это необхо­ди­мость, т.к. вызов Native.loadLibrary посред­ством reflection строит карту интер­фейса и его структур и, если вынести эту структуру из интер­фейса, то карта будет непра­вильной. Ладно, если бы была ошибка, так структура просто будет ошибочно заполнена методом EnumPrinters – например, вместо имени принтера в поле pPrinterName будет только первая буква имени.

У структуры PRINTER_INFO_2 есть еще пара особен­ностей: она должна содержать конструктор без параметров и переопре­делять метод protected List getFieldOrder() – строгая после­до­ва­тель­ность и имено­вание полей.

Вот и все. Запустив тест, получим в консоли список принтеров и их драйверов:

PrinterName = Samsung SCX-4x28 Series PCL6, DriverName = Samsung SCX-4x28 Series PCL6
PrinterName = Samsung CLX-3180 Series, DriverName = Samsung CLX-3180 Series
PrinterName = PDF Creator, DriverName = CUSTPDF Writer
PrinterName = FinePrint, DriverName = FinePrint 7
PrinterName = Fax, DriverName = Microsoft Shared Fax Driver

Это именно то, что требовалось.
Как же можно еще упростить эту задачу? Выглядит все это все равно чересчур громоздко.
Например, нам не нужны все 21 поля структуры PRINTER_INFO_2, а только два – PrinterName и DriverName.
Посмотрим, как справ­ляется с этим .NET – ведь это неотъ­ем­лемая часть Microsoft Windows.
Код для консольного прило­жения .NET будет выглядеть так:

public class Tester
{
    public static void Main()
    {
        System.Printing.LocalPrintServer localPrintServer = new
        System.Printing.LocalPrintServer(System.Printing.PrintSystemDesiredAccess.AdministrateServer);
        foreach (var printer in localPrintServer.GetPrintQueues())
        {
            System.Console.WriteLine("PrinterName = {0}, DriverName = {1}", printer.FullName, printer.QueueDriver.Name);
        }
        System.Console.Read();
    }
}

Результат выводится на консоль:

PrinterName = Samsung SCX-4x28 Series PCL6, DriverName = Samsung SCX-4x28 Series PCL6
PrinterName = Samsung CLX-3180 Series, DriverName = Samsung CLX-3180 Series
PrinterName = PDF Creator, DriverName = CUSTPDF Writer
PrinterName = FinePrint, DriverName = FinePrint 7
PrinterName = Fax, DriverName = Microsoft Shared Fax Driver

Хм… То же самое. Значит мы на правильном пути.

Как теперь обернуть этот код в «нативную» библиотеку, получить к ней доступ через JNA и забрать результат в удобном для нашего проекта виде?
Начнем с того, что .NET не «нативная» среда — у нее свои CLR (Common Language Runtime), CIL (Common Intermediate Language) и CLI (Common Language Infrastructure-Standard), и .NET-DLL будет отлично линко­ваться другой библио­текой или программой .NET, но никак не как «нативная» библиотека к С- и Java-программам.

Как же быть?

На помощь приходит Unmanaged Exports (DllExport for .Net).

Ее можно подключить как nuget-плагин через Package Manager Console с помощью команды:

PM> Install-Package UnmanagedExports

Либо просто взять у произ­во­дителя архив с плагином UnmanagedExportLibrary.zip и скопи­ровать его в каталог шаблонов проек­ти­ро­вания Microsoft Visual Studio.

Обычно это My DocumentsVisual Studio 20**TemplatesProjectTemplates.

Потом создать новый проект C# на базе шаблона UnmanagedExportLibrary и наша «нативная» библиотека Winspool.dll почти готова.
Добавим в нее стати­ческий класс Export и стати­ческую функцию GetPrinterInfo:

using System;
using System.Text;
using RGiesecke.DllExport;
 
public static class Export
{
    [DllExport("GetPrinterInfo")]
    public static string GetPrinterInfo()
    {
        try
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            System.Printing.LocalPrintServer localPrintServer = new System.Printing.LocalPrintServer(System.Printing.PrintSystemDesiredAccess.AdministrateServer);
            foreach (var printer in localPrintServer.GetPrintQueues())
            {
                sb.Append(printer.FullName).Append(";").Append(printer.QueueDriver.Name).Append(";");
            }
            return sb.ToString();
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }
}

Стати­ческий класс и стати­ческая функция – это необхо­димое условие для приме­нения атрибута DllExport из библиотеки RGiesecke.DllExport. Таким образом, функция станет «нативной» в библиотеке и к ней можно будет непосред­ственно обращаться через JNA.

Функция GetPrinterInfo собирает инфор­мацию о принтерах и их драйверах в строку с разде­ли­телем «;», т.е. если потом преоб­ра­зовать эту строку по разде­лителю в массив строк, то по нечетным индексам будет имя принтера, а по четным – имя драйвера. Очень полезным для нас тут будет то, что DllExport может передавать простые типы в качестве параметров и возвра­щаемых значений функций, и к счастью для нас, что в этот список входит string.

Скомпи­лируем библиотеку Winspool.dll для платформы х86.

Код на Java выглядит так:

import com.sun.jna.Native;
import java.io.File;
 
public class WinSpoolTest {
 
    public interface Winspool extends com.sun.jna.Library {
        public String GetPrinterInfo();
    };
 
    public static void main(String[] args){
        final String path = new File("").getAbsolutePath() + "\lib\Winspool.dll";
        final Winspool lib = (Winspool) Native.loadLibrary(path, Winspool.class);
 
        final String res = lib.GetPrinterInfo();
        final String[] arr = res.split(";");
 
        for (int i = 0; i < arr.length; i += 2){
            System.out.printf("PrinterName = %1$2s, DriverName = %2$2sn", arr[i], arr[i+1]);
        }
    }
}

Выглядит значи­тельно проще, не правда ли?

Но что-то все равно бросается в глаза своим несовер­шен­ством… Да, это распо­ло­жение библиотеки Winspool.dll в папке lib, рядом с классом, и ее поиск по пути в файловой системе:

final String path = new File(“”).getAbsolutePath() + “\lib\Winspool.dll”;

В данном случае это не критично, но что делать, если проект как-то хитро компи­ли­руется, использует специ­альные папки для ресурсов, или динами­чески ориен­ти­рован на Java опреде­ленной разряд­ности – 64 бита или 32? Как сделать так, чтобы нам упростить поиск место­рас­по­ло­жения библиотеки? И как подго­товить «нативную» библиотеку для разной разряд­ности, да еще отследить в Java проекте, когда и какую использовать?

Вот тут выступает еще одно досто­инство JNA – автома­ти­ческое скани­ро­вание и нахож­дение «нативных» библиотек.

Если сделать так:
1 – где-нибудь создать две папки — win32-x86 и win32-x86-64
2 — скомпи­ли­ровать «нативную» библиотеку с атрибутом х86, и положить ее в папку win32-x86
3 — скомпи­ли­ровать с атрибутом х64, и положить в win32-x86-64
4 — создать из этих двух папок zip-архив
5 — переиме­новать его в jar
6 — подключить его к Java-проекту
то JNA автома­ти­чески подключает версию «нативной» библиотеки соответ­ственно разряд­ности Java.

Код станет еще проще, и нам не придется устра­ивать поиск библиотеки Winspool.dll, контроль соответ­ствия разряд­ности Java и библиотеки Winspool.dll.

import com.sun.jna.Native;
 
public class WinSpoolTest2 {
 
    public interface Winspool extends com.sun.jna.Library {
        public String GetPrinterInfo();
    };
 
    public static void main(String[] args){
        final Winspool lib = (Winspool) Native.loadLibrary("Winspool", Winspool.class);
 
        final String res = lib.GetPrinterInfo();
        final String[] arr = res.split(";");
 
        for (int i = 0; i < arr.length; i += 2){
            System.out.printf("PrinterName = %1$2s, DriverName = %2$2sn", arr[i], arr[i+1]);
        }
    }
}

Ну и напоследок, можно сделать еще красивее. Благодаря тому, что «нативная» библиотека .NET может возвращать строку неогра­ни­ченной длинны, то исполь­зо­вание результата с разде­ли­телем выглядит не очень дружественно.

Что более всего подходит для передачи данных в виде строки? Правильно – XML. Попробуем передать в качестве результата «нативной» библиотеки XML-сериа­ли­зо­ванный объект, а на стороне Java десери­а­лизуем в свой точно такой же объект.

На C# есть несколько возмож­ностей XML-сериа­ли­зации объектов, но сразу сделаю замечание, что распро­стра­ненная сериа­ли­зация из библиотеки System.Xml.Serialization не работает, если исполь­зовать ее в «нативной» библиотеке.

Будет ошибка System.IO «Illegal characters in path», хотя никакого IO при этом не исполь­зуется – это какой-то баг .NET, который пока не исправлен и в .NET 4.5.

К счастью есть другой механизм XML-сериа­ли­зации в библиотеке System.Runtime.Serialization.

Добавим к .NET-проекту класс PrintInfoList:

using System;
using System.Runtime.Serialization;
using System.Text;
using System.IO;
using System.Collections.Generic;
 
[DataContract(Name = "PrintInfoList")]
public class PrintInfoList
{
    [DataContract(Name = "PrintInfo")]
    public class PrintInfo
    {
        [DataMember(Name = "PrinterName")]
        public string PrinterName
        { get; set; }
 
        [DataMember(Name = "DriverName")]
        public string DriverName
        { get; set; }
    }
 
    private List<PrintInfo> list = new List<PrintInfo>();
 
    [DataMember(Name = "List")]
    public List<PrintInfo> List
    { get { return list; } }
 
    public String Serialize()
    {
        DataContractSerializer serializer = new DataContractSerializer(typeof(PrintInfoList));
        using (MemoryStream memoryStream = new MemoryStream())
        {
            serializer.WriteObject(memoryStream, this);
            memoryStream.Flush();
            string result = Encoding.UTF8.GetString(memoryStream.ToArray());
            result = System.Text.RegularExpressions.Regex.Replace(result, "<PrintInfoList.*?>", "<PrintInfoList>");
            return result;
        }
    }
}

Здесь можно видеть корневой класс PrintInfoList, который является списком объектов PrintInfo. Стоит обратить внимание на исполь­зо­вание атрибутов библиотеки System.Runtime.SerializationDataContract и DataMember. Их приме­нение должно быть совер­шенно очевидным – DataContract описывает объект, а DataMember – данные объекта, в данном случае это открытые поля. Кроме того, в конце метода десери­а­ли­зации в полученной XML-строке применена замена секции <PrintInfoList… со всеми простран­ствами имен Namespaces на — просто секцию <PrintInfoList>. Это нужно для упрощения примера, иначе придется обеспе­чивать обработку всех Namespaces на стороне Java.

Далее в класс Export добавим новую функцию GetPrinterInfo2, возвра­щающую запол­ненный и сериа­ли­зо­ванный объект PrintInfoList в виде XML-строки:

[DllExport("GetPrinterInfo2")]
public static string GetPrinterInfo2()
{
    try
    {
        PrintInfoList pil = new PrintInfoList();
        System.Printing.LocalPrintServer localPrintServer = new System.Printing.LocalPrintServer(System.Printing.PrintSystemDesiredAccess.AdministrateServer);
        foreach (var printer in localPrintServer.GetPrintQueues())
        {
            pil.List.Add(new PrintInfoList.PrintInfo
            {
                PrinterName = printer.FullName,
                DriverName = printer.QueueDriver.Name
            });
        }
        return pil.Serialize();
    }
    catch (Exception ex)
    {
        return ex.Message;
    }
}

Теперь вернемся к Java. Чтобы десери­а­ли­зовать XML-строку — результат метода GetPrinterInfo2 библиотеки Winspool.dll, создадим полный аналог объектов на Java:

import com.sun.jna.Native;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
 
public class WinSpoolTest3 {
 
    @XmlAccessorType(XmlAccessType.NONE)
    @XmlRootElement(name = "PrintInfo")
    public static class PrintInfo {
         
        @XmlElement(name = "PrinterName")
        public String printerName;
 
        @XmlElement(name = "DriverName")
        public String driverName;
    }
 
    @XmlAccessorType(XmlAccessType.NONE)
    @XmlRootElement(name = "PrintInfoList")
    public static class PrintInfoList {
 
        @XmlElementWrapper(name = "List")
        @XmlElements({@XmlElement(name = "PrintInfo", type = PrintInfo.class)})
        public List<PrintInfo> list;
 
        public static PrintInfoList deserialize(String xml) {
            try {
                final InputStream inputStream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
                try {
                    final JAXBContext context = JAXBContext.newInstance(PrintInfoList.class);
                    final Unmarshaller unmarshaller = context.createUnmarshaller();
                    return (PrintInfoList)unmarshaller.unmarshal(inputStream);
                } finally {
                    inputStream.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return null;
        }
    }
 
    public interface Winspool extends com.sun.jna.Library {
        public String GetPrinterInfo2();
    };
 
    public static void main(String[] args){
        final Winspool lib = (Winspool) Native.loadLibrary("Winspool", Winspool.class);
        final String res = lib.GetPrinterInfo2();
 
        final PrintInfoList pil = PrintInfoList.deserialize(res);
 
        for(final PrintInfo pi : pil.list){
            System.out.printf("PrinterName = %1$2s, DriverName = %2$2sn", pi.printerName, pi.driverName);
        }
    }
}

Т.е. XML-строка десери­а­ли­зуется в экземпляр PrintInfoList, который представляет собой список объектов PrintInfo, и который теперь гораздо удобнее и нагляднее исполь­зовать в любых частях проекта.

На базе полученного шаблона «нативная» DLL -> JNA -> Java можно создавать много разных и интересных межплат­фор­менных проектов. На C# можно писать библиотеки-оболочки, упрощающие работу с «внутрен­но­стями» Microsoft Windows, которые трудно реали­зуемы или вообще недоступны для Java, а качестве обмена между .NET и Java процессами исполь­зовать XML-сериа­ли­зо­ванные объекты. Ведь этот принцип можно исполь­зовать и в обратном направ­лении, т.е. от Java к .NET, и таким способом передавая параметры и прочие данные для обработки в «нативной» DLL через XML-сериа­ли­зо­ванные объекты.

Исходные коды и прочие ресурсы:

Все исходные коды можно найти здесь:
src-jna-for-access-to-native-com-dll-library.zip

В январе 2016 года мы переехали в новый офис. Пожалуйста обратите внимание, что новый адрес компании изменился на:

Intechcore GmbH
Keltenring 17
82041 Oberhaching bei München

Телефоны, факсы и емайл адреса остались прежними.

Будет рады вашим контактам!