Введение


Данный модуль / библиотека (.dll) позволит Вам взаимодействовать с базой данных КАБИС напрямую, при помощи функций экспорта, без использования графической обёртки, на которую помимо этого наложено множество ограничений.

На официальном сайте разработчика есть упоминание про API, но более подробную информацию по этому поводу, кроме пункта с описанием этой возможности, мне найти не удалось :(

Но, так как эта возможность даёт выполнять ряд определённых задач с базой данных библиотеки, Вы и можете наблюдать решение данной проблемы в виде модуля, где имеются все необходимые функции экспорта для манипуляции данными в базе данных.

База данных работает при помощи драйвера ODBC, поэтому решение данной проблемы не заставило себя долго ждать. Так как я не смог открыть файл базы данных при помощи MS Access и других программ управления базами данных, этот драйвер оставался единственной надеждой.

В будущем планируется доработка модуля и последующее добавление новых функций для более гибкого взаимодействия с базой данных библиотеки.

Версия документации: 0.2
Версия библиотек (модулей): 0.2

P.S: Модуль kapi32u (utils).dll необходим для выполнения специфических задач, таких как получение пароля от БД из памяти программы. Возможно это можно сделать каким-то иным путём, но пока я нашёл только это решение данной проблемы.

Начало работы с библиотеками kapi32.dll и kapi32u.dll


Все необходимые функции экспорта библиотек и их описание расположены в документации ниже.

Функции экспорта kapi32.dll:

Функции экспорта kapi32u.dll:

Заглавия


Разделы



[+] Работа с kapi32.dll

PtrToStr


string PtrToStr(IntPtr intPtr);

Преобразовывает указатель на массив из символов в текст.
Возвращаемый результат:

Аргументы:

  1. [in] intPtr - Указатель на массив символов. Обычно используется только для преобразования результата возврата функции ScanForPass, для получения строки (пароля от базы данных).

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static string PtrToStr(IntPtr intPtr);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        //Импортировать функции необходимо именно так, как показано в примере, указывая согласование о вызове

        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            //Присвоение строковой переменной результата выполнения функции PtrToStr
            string strDBPassword = PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"));

            Console.WriteLine("Пароль от базы данных: {0}", strDBPassword);
            Console.ReadKey();
        }
    }
}

OpenDataBase


bool OpenDataBase(string strDataBase, string strPassword);

Позволяет установить соединение с локальной базой данных.
Возвращаемый результат:

Аргументы:

  1. [in] strDataBase - Путь до Вашей локальной базы данных. Для примера: C:\\KABIS\\Data\\Books.dbx;
  2. [in] strPassword - Пароль для авторизации в базе данных. Извлекается путём вызова функции ScanForPass из библиотеки kapi32u.dll.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static bool OpenDataBase(string strDataBase, string strPassword);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");

                //Здесь можно выполнить какой-либо код перед закрытием базы данных...

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

ДОПОЛНИТЕЛЬНО:
Вы можете открывать базу данных, даже если она находится на каком-либо локальном компьютере в сети, либо по названию компьютера, либо по его IP-адресу. Подробную инструкцию о том, как можно реализовать доступ к сетевой папке Вы сможете найти здесь [клик!].

Только учтите, если другая база данных на сервере использует другой пароль для авторизации, Вам необходимо будет удалить параметр DBPassword в реестре системы по следующему пути: HKEY_CURRENT_USER\SOFTWARE\kapi32, чтобы функция ScanForPass смогла его пересоздать.

Более подробно о данной информации можно узнать в описании к функции ScanForPass.

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            //Открываем базу данных по имени компьютера и пути к сетевой папке.

            if (OpenDataBase("\\\\DESKTOP-IQ3MQPS\\KABIS\\Data\\Books.dbx", PtrToStr(
                ScanForPass("\\\\DESKTOP-IQ3MQPS\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта через сетевую папку по имени компьютера!");
                CloseDataBase();
            }

            //Открываем базу данных по IP-адресу компьютера и пути к сетевой папке.

            if (OpenDataBase("\\\\192.168.100.72\\KABIS\\Data\\Books.dbx", PtrToStr(
                ScanForPass("\\\\192.168.100.72\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта через сетевую папку по IP-адресу компьютера!");
                CloseDataBase();
            }

            Console.ReadKey();
        }
    }
}

EnumTables


string EnumTables();

Позволяет перечислить все таблицы, которые находятся в базе данных. Функция возвращает строковый результат в формате JSON. Все необходимые наименования таблиц можно спарсить по параметру "Tables" при помощи библиотеки Newtonsoft.JSON для платформы .NET.
Возвращаемый результат:

Аргументы: Функция не принимает аргументов.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static string EnumTables();

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");
                string strTables = EnumTables();

                if (!string.IsNullOrEmpty(strTables))
                {
                    Console.WriteLine(strTables);
                }
                else
                {
                    Console.WriteLine("Не удалось получить перечень таблиц из базы данных!");
                }

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

GetTableCount


int GetTableCount();

Возвращает число таблиц в базе данных.
Возвращаемый результат:

Аргументы: Функция не принимает аргументов.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static int GetTableCount();

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");
                int iTables = GetTableCount();

                if (iTables != -1)
                {
                    Console.WriteLine("Число таблиц в текущей базе данных: {0}", iTables);
                }
                else
                {
                    Console.WriteLine("Не удалось получить число таблиц в базе данных.");
                }

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

EnumFields


string EnumFields(string strTable);

Позволяет перечислить все поля таблицы, указанной в аргументе функции. Функция возвращает строковый результат в формате JSON.
Возвращаемый результат:

Аргументы:

  1. [in] strTable - Наименование таблицы из которой Вы хотите получить список полей.

  2. Вы можете воспользоваться библиотекой Newtonsoft.JSON для парсинга результата возврата функции EnumTables и запустить цикл, который будет перечислять все поля для i-таблицы в массиве.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static string EnumFields(string strTable);

C# - Пример кода

using System;
using System.Text;
using System.Linq;
using Newtonsoft.Json.Linq;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");
                string strTables = EnumTables();

                if (!string.IsNullOrEmpty(strTables))
                {
                    JToken jtTables = JObject.Parse(strTables)["Tables"];

                    for (int a = 0; a < jtTables.Count(); a++)
                    {
                        Console.WriteLine("[+] Поля для таблицы \"{0}\":\n-------------------------", 
                            jtTables[a].ToString());
                        string strFields = EnumFields(jtTables[a].ToString());

                        if (!string.IsNullOrEmpty(strFields))
                        {
                            JToken jtFields = JObject.Parse(strFields)["Fields"];

                            for (int b = 0; b < jtFields.Count(); b++)
                                Console.WriteLine((b + ": " + jtFields[b]));
                        }

                        Console.WriteLine("-------------------------\n");
                    }

                    Console.WriteLine("Все поля всех таблиц были перечислены!");
                }
                else
                    Console.WriteLine("Не удалось получить перечень таблиц из базы данных!");

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

GetFieldCount


int GetFieldCount(string strTable);

Возвращает число полей в таблице, указанной в аргументе функции.
Возвращаемый результат:

Аргументы:

  1. [in] strTable - Наименование таблицы из которой Вы хотите получить количество полей.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static int GetFieldCount(string strTable);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("Кол-во поле в таблице \"Books\": {0}", GetFieldCount("Books"));

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

SelectAllFrom


string SelectAllFrom(string strTable, bool bOutput);

Извлекает все данные таблицы, указанной в аргументе, вместе с полями через запрос "SELECT * FROM `%TableName%`;".
Возвращаемый результат:

Аргументы:

  1. [in] strTable - Наименование таблицы из которой Вы хотите выгрузить все поля вместе с их значением;
  2. [in] bOutput - Выводит в консоль текущую строку (текст) во время выполнения выгрузки.

    Это полезно в тех случаях, когда таблица содержит слишком много записей и их выгрузка может занять продолжительное время, то есть, Вы можете ожидать очень долго, пока функция вернёт Вам значение. Для того, чтобы убедиться, что записи выгружаются из базы данных, Вы можете в качестве аргумента указать значение true.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static string SelectAllFrom(string strTable, bool bOutput);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string SelectAllFrom(string strTable, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                string strResult = SelectAllFrom("Librarians", false);
                Console.WriteLine(strResult);

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

CreateCustomQuery


string CreateCustomQuery(string strQuery);

Позволяет выполнять кастомные запросы к базе данных. Для примера "SELECT `id`, `Password`, `UserPC` FROM `Librarians`;".
Возвращаемый результат:

Аргументы:

  1. [in] strQuery - Ваш кастомный запрос к определённой таблице в базе данных. Для примера "SELECT `id`, `Password`, `UserPC` FROM `Librarians`;".

  2. Вы можете составлять любые запросы, включая такие ключевые слова как WHERE, CASE, CONCAT, INNER JOIN, LEFT JOIN, RIGHT JOIN, ON и другие. Вообщем, весь функционал стандартного SQL.

    Получить перечень таблиц и их поля можно через вызов функций EnumTables и EnumFields.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static string CreateCustomQuery(string strQuery);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        /* Тут находятся все функции экспорта, которые содержит библиотека kapi32.dll и kapi32u.dll */

        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string SelectAllFrom(string strTable, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string CreateCustomQuery(string strQuery);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableRecords(string strTable);
        
        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");

                //Выполняем кастомный запрос, чтобы получить таблицу с указанными полями
                string strQuery = CreateCustomQuery("SELECT `id`, `Password`, `UserPC` FROM `Librarians`;");

                if (!string.IsNullOrEmpty(strQuery))
                    Console.WriteLine("---------------------------------\n" + strQuery);
                else
                    Console.WriteLine("Произошла ошибка во время выполнения кастомного запроса!");

                if (CloseDataBase())
                {
                    Console.WriteLine("---------------------------------");
                    Console.WriteLine("Соединение с базой данных было закрыто.");
                }
            }
            else
                Console.WriteLine("Не удалось открыть базу данных.");

            Console.ReadKey();
        }
    }
}

РЕЗУЛЬТАТ ВЫЗОВА ФУНКЦИИ:
Ниже представлен результат успешного выполнения функции с указанным кастомным запросом к базе данных. Вы можете составлять любые запросы к базе данных, комбинируя их с другими ключевыми словами.

🛠️ Командная строка

База данных была успешно открыта!
---------------------------------
id      Password        UserPC
1       kabis   DESKTOP-AE57DMC
2               LIBRARY-PC
3       12345   LIB-LIBRARY
4       1234579 LIBRARY-PC
5       12345   KABIS
6       12345   PC-82178739E0
7       12345   User
10      12345
11      12345
12      12345
13      12345
14      12345
15      1234
16      1234
17      1234
18      1234
19      1234
20      1234

---------------------------------
Соединение с базой данных было закрыто.
_

UnloadTable


string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

Позволяет выгрузить все записи таблицы вместе с полями в какой-либо файл с указанными разделителями.
Возвращаемый результат:

Аргументы:

  1. [in] strTable - Наименование таблицы из которой Вы хотите выгрузить все поля вместе с их значением;
  2. [in] strFile - Имя файла, в который Вы хотите сохранить выгруженные данные из таблицы;

    В случае отсутствия аргумента (null) или передачи в него пустого значения "" (string.Empty) выгрузка данных таблицы произойдёт без сохранения их в указанный файл. В любом случае, результат возвращаемого значения функции UnloadTable Вы сможете записать в какой-либо файл самостоятельно, при помощи класса File, через один из имеющихся методов, к примеру File.WriteAllText("MyTable.txt", "Какой-то текст или данные из таблицы.");.
    Для этого Вам нужно будет подключить пространство имён "System.IO" (using System.IO;).

  3. [in] iType - Номер разделителя при выгрузке столбцов. Библиотека поддерживает выгрузку со следующими разделителя:

    • 0 - Выгрузка без разделителя, то есть обычным списком, который прописан в алгоритме библиотеки;
    • 1 - Разделителем будет являться символ "," (запятая);
    • 2 - Разделителем будет являться символ ";" (точка с запятой);
    • 3 - Разделителем будет являться символ ":" (двоеточие);
    • 4 - Разделителем будет являться символ "\t" (знак табуляции).

    Если в аргументе iType функции UnloadTable Вы укажите значение > 4 или < 0, то функция вернёт Вам пустой результат "" (string.Empty).

  4. [in] bOutput - Выводит в консоль текущую строку (текст) во время выполнения выгрузки.

  5. Это полезно в тех случаях, когда таблица содержит слишком много записей и их выгрузка может занять продолжительное время, то есть, Вы можете ожидать очень долго, пока функция вернёт Вам значение. Для того, чтобы убедиться, что записи выгружаются из базы данных, Вы можете в качестве аргумента указать значение true.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string SelectAllFrom(string strTable, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");
                
                if (!string.IsNullOrEmpty(UnloadTable("Librarians", "Users.txt", 1, false)))
                    Console.WriteLine("Данные таблицы были успешно выгружены в файл \"Users.txt\".");
                else
                    Console.WriteLine("Не удалось выгрузить данные таблицы.");

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

GetTableRecords


int GetTableRecords(string strTable);

Получает количество записей в таблице, указанной в аргументе функции. Например, для получения количества книг во всех каталогах (для получения записей в определённом каталоге нужно делать кастомный запрос).
Возвращаемый результат:

Аргументы:

  1. [in] strTable - Наименование таблицы в которой Вы хотите узнать количество записей.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static int GetTableRecords(string strTable);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string SelectAllFrom(string strTable, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableRecords(string strTable);
        
        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");
                int iRecords = GetTableRecords("Books");

                if (iRecords != -1)
                    Console.WriteLine("Кол-во книг в библиотечном фонде: {0}", iRecords);
                else
                    Console.WriteLine("Не удалось получить кол-во записей для текущей таблицы.");

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}

CloseDataBase


bool CloseDataBase();

Закрывает соединение с базой данных. Должна вызываться после завершения работы с базой данных.
Возвращаемый результат:

Аргументы: Функция не принимает аргументов.

C# - Пример импорта

[DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
extern public static bool CloseDataBase();

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        /* Тут находятся все функции экспорта, которые содержит библиотека kapi32.dll и kapi32u.dll */

        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string SelectAllFrom(string strTable, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string CreateCustomQuery(string strQuery);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableRecords(string strTable);
        
        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"))))
            {
                Console.WriteLine("База данных была успешно открыта!");

                //Здесь можно что-то выполнить перед закрытием базы данных...

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}


[+] Работа с kapi32u.dll

Модуль (библиотека) содержит в себе всего лишь одну экспортируемую функцию. Которая выполняет своё главное действие только один раз. Более подробнее написано в описании к функции.

ScanForPass


IntPtr ScanForPass(string strAppName);

Извлекает из памяти процесса (программы) пароль для базы данных.

Так как данные о пароле не хранятся в реестре или в файловой системе компьютера, Вам необходимо будет вызывать эту функцию и результат её выполнения передавать во второй аргумент функции OpenDataBase для корректного установления соединения с базой данных.
Возвращаемый результат:

Аргументы:

  1. [in] strAppName - Путь до Вашего приложения KABIS.

    Для того, чтобы функция могла получить пароль от базы данных, ей необходимо запустить библиотечную программу для того, чтобы в её памяти получить пароль.

    НО БУДЬТЕ ВНИМАТЕЛЬНЫ!
    Перед вызовом этой функции рекомендуется закрыть все экземпляры программы КАБИС, чтобы не потерять сохранённые в ней данные, иначе функция сделает это принудительно, так как ей необходимо запустить программу и получить правильный экземпляр приложения для того, чтобы корректно извлечь из него пароль для базы данных.

    ДОПОЛНИТЕЛЬНО:
    Также, после первого получения пароля от базы данных, функция создаёт раздел в реестре системы по следующему пути: HKEY_CURRENT_USER\SOFTWARE\kapi32 с некоторыми ключами, одним из которых является ключ DBPassword. При следующем вызове данной функции она уже будет проверять реестр на наличие данного ключа, чтобы лишний раз не запускать библиотечное приложение.

    В случае, если Вы удалите этот раздел или данный ключ, функция ScanForPass вновь запустит приложение для того, чтобы извлечь из его памяти пароль.

    Также, Вы можете присвоить результат функции какой-то строковой переменной и вывести её в консоль, а после, передавать эту строку в качестве второго аргумента функции OpenDataBase для того, чтобы не использовать вызов функции ScanForPass.

C# - Пример импорта

[DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
extern public static IntPtr ScanForPass(string strAppName);

C# - Пример кода

using System;
using System.Text;
using System.Runtime.InteropServices;

namespace KabisAPITest
{
    internal class Program
    {
        /* Тут находятся все функции экспорта, которые содержит библиотека kapi32.dll и kapi32u.dll */

        [DllImport("kapi32u.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static IntPtr ScanForPass(string strAppName);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string PtrToStr(IntPtr intPtr);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool OpenDataBase(string strDataBase, string strPassword);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumTables();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableCount();

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string EnumFields(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetFieldCount(string strTable);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string SelectAllFrom(string strTable, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string CreateCustomQuery(string strQuery);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static string UnloadTable(string strTable, string strFile, int iType, bool bOutput);

        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static int GetTableRecords(string strTable);
        
        [DllImport("kapi32.dll", CallingConvention = CallingConvention.StdCall)]
        extern public static bool CloseDataBase();

        static void Main(string[] args)
        {
            Console.InputEncoding = Encoding.UTF8;
            Console.OutputEncoding = Encoding.UTF8;

            string strDBPassword = PtrToStr(ScanForPass("C:\\KABIS\\KABIS.EXE"));
            Console.WriteLine("Пароль от базы данных: {0}", strDBPassword);

            if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", strDBPassword))
            {
                Console.WriteLine("База данных была успешно открыта!");

                //Здесь можно что-то выполнить перед закрытием базы данных...

                if (CloseDataBase())
                    Console.WriteLine("Соединение с базой данных было закрыто.");
            }

            Console.ReadKey();
        }
    }
}


[+] Вызов функций экспорта на других языках

Также, Вы можете импортировать функции экспорта в свою программу и на других языках программирования, таких как C++ или Python, чтобы выполнять все доступные действия с базой данных КАБИС.

С++


C++ - Пример кода

#include <iostream>
#include <string>
#include <string.h>
#include <Windows.h>

using namespace std;

//Создаём прототипы импортируемых функций
typedef const char* (__stdcall* ScanForPassFn)(const char* cchAppName);
ScanForPassFn ScanForPass;

typedef bool (__stdcall* OpenDataBaseFn)(const char* cchDataBase, const char* cchPassword);
OpenDataBaseFn OpenDataBase;

typedef const char* (__stdcall* UnloadTableFn)(const char* cchTable, const char* cchFile, int iType, bool bOutput);
UnloadTableFn UnloadTable;

typedef bool (__stdcall* CloseDataBaseFn)();
CloseDataBaseFn CloseDataBase;

int main()
{
	setlocale(LC_ALL, "");

	HMODULE hKapi32 = LoadLibraryA("kapi32.dll");
	HMODULE hKapi32u = LoadLibraryA("kapi32u.dll");

	if (hKapi32 && hKapi32u)
	{
		ScanForPass = (ScanForPassFn)GetProcAddress(hKapi32u, "ScanForPass");
		OpenDataBase = (OpenDataBaseFn)GetProcAddress(hKapi32, "OpenDataBase");
		UnloadTable = (UnloadTableFn)GetProcAddress(hKapi32, "UnloadTable");
		CloseDataBase = (CloseDataBaseFn)GetProcAddress(hKapi32, "CloseDataBase");

		//Лучше сделать массив и проверить всё это в цикле
		if (ScanForPass && OpenDataBase
			&& UnloadTable && CloseDataBase)
		{
			if (OpenDataBase("C:\\KABIS\\Data\\Books.dbx", ScanForPass("C:\\KABIS\\KABIS.EXE")))
			{
				cout << "База данных была успешно открыта!\n";
				string strTable = UnloadTable("Librarians", nullptr, 0, false);

				if (!strTable.empty())
					cout << strTable << "\n";
				else
					cout << "Не удалось выгрузить таблицу.\n";

				if (CloseDataBase())
					cout << "Соединение с базой данных было закрыто.\n";
			}
			else
				cout << "Не удалось открыть базу данных.\n";
		}
		else
			cout << "Не удалось получить адреса одной или нескольких функций.\n";
	}
	else
		cout << "Не удалось загрузить один или несколько модулей в процесс.\n";

	system("pause");
	return 0;
}

Python


Python - Пример кода

import ctypes as lib

kapi32 = lib.WinDLL("C:\\PyKapi32\\kapi32.dll")
kapi32u = lib.WinDLL("C:\\PyKapi32\\kapi32u.dll")

ScanForPass = kapi32u.ScanForPass
ScanForPass.restype = lib.c_char_p
ScanForPass.argtypes = [lib.c_char_p]

OpenDataBase = kapi32.OpenDataBase
OpenDataBase.restype = lib.c_bool
OpenDataBase.argtypes = [lib.c_char_p, lib.c_char_p]

UnloadTable = kapi32.UnloadTable
UnloadTable.restype = lib.c_char_p
UnloadTable.argtypes = [lib.c_char_p, lib.c_char_p, lib.c_int, lib.c_bool]

CloseDataBase = kapi32.CloseDataBase
CloseDataBase.restype = lib.c_bool

if (ScanForPass != 0
    and OpenDataBase != 0
    and UnloadTable != 0
    and CloseDataBase != 0):
    DataBase = b"C:\\KABIS\\Data\\Books.dbx"
    Password = ScanForPass(b"C:\\KABIS\\KABIS.EXE")

    if (len(Password) > 0):
        if (OpenDataBase(DataBase, Password)):
            print("База данных была успешно открыта!")
            Table = UnloadTable(b"Librarians", b"", 0, False).decode("cp1251")

            if (len(Table) > 0):
                print(Table)
            else:
                print("Не удалось выгрузить таблицу из базы данных.")
        
        if (CloseDataBase()):
            print("База данных была успешно закрыта!")
else:
    print("Не удалось получить адрес одной или нескольких функций.")

input("Нажмите клавишу Enter или Ctrl + C для завершения выполнения программы...\n")

ВНИМАНИЕ!
Ваше приложение должно быть x32-битной разрядности, иначе ни одна из библиотек не будет работать или при запуске программы у Вас будет возникать ошибка различий совместимости библиотеки и приложения.


Заключение


Вы можете использовать все функции экспорта так, как захотите, всё зависит только от Вашего воображения. Теперь, при помощи данного инструмента у Вас появится возможность интеграции библиотечной системы KABIS с другими корпоративными системами, по крайней мере у меня.

Также, в случае обнаружения проблем библиотеки или проблем при работе с ней, Вы можете задать мне любые вопросы по этому поводу в Discord.

Ну, вроде бы ничего не забыл описать. В любом случае, документация будет обновляться параллельно с добавлением нового функционала в библиотеку (модуль).