На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Следующие правила действуют в данном разделе в дополнение к общим Правилам Форума
1. Здесь обсуждается Java, а не JavaScript! Огромная просьба, по вопросам, связанным с JavaScript, SSI и им подобным обращаться в раздел WWW Masters или, на крайний случай, в Многошум.
2. В случае, если у вас возникают сомнения, в каком разделе следует задать свой вопрос, помещайте его в корневую ветку форума Java. В случае необходимости, он будет перемещен модераторами (с сохранением ссылки в корневом разделе).

3. Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.
4. Не рекомендуется создавать несколько несвязанных вопросов в одной теме. Пожалуйста, создавайте по одной теме на вопрос.
Модераторы: dark_barker, wind
  
> конвертировать jstring to LCPWSTR
    Доброго времени суток.
    Ситуация следующая. Существует сторонняя dll-библиотека без доступа к исходникам(STF.dll) и программа на java. Необходимо использовать функции библиотеки в программе с помощью JNI(обязательное условие).
    Сейчас подключение выглядит так.

    java:
    ExpandedWrap disabled
      public class DllUse {
          private static String dirPath;
          static{
              try{  
                  dirPath = ..путь..; ///путь до библиотеки
                  System.load(dirPath+"libDllUse.dll");                    
              } catch(Exception ex) {}
          }
       
          public static int connectDl(){
              return new DllUse().connectDll(dirPath+"STF.dll");
          }
          private native int connectDll(String path);
      }


    jni прослойка libDllUse.с
    ExpandedWrap disabled
      static HINSTANCE mod;
      JNIEXPORT jint JNICALL Java_DllUse_connectDll
      (JNIEnv *env, jobject obj, jstring path)
      {  
          const char* ipstr=(*env)->GetStringUTFChars(env, path, NULL);
       
          wprintf((const wchar_t *)ipstr);  //стр1
       
          mod=LoadLibrary((const wchar_t *)ipstr);
          (*env)->ReleaseStringUTFChars(env, path, ipstr1);
          if (mod == NULL) {  return -1;}
          return 1;
      }

    После вызова функция connectDl() возвращает -1, следовательно подключение не происходит. стр1 выводит:
    ..путь..\STF.dll_Разнообразная_Абракадабра

    Как скормить jstring path функции
    ExpandedWrap disabled
      HMODULE WINAPI LoadLibrary(_In_ LPCTSTR lpFileName);
    ?
    Или что ещё можно придумать в рамках заданных условий?
    Буду рада любой помощи.

    PS.
    ExpandedWrap disabled
      LoadLibrary(TEXT("..путь..\STF.dll"));
    отлично работает, но путь до библиотек задается в java-программе (обязательное условие);
      Цитата Anka-BOIN @
      public static int connectDl(){
      return new DllUse().connectDll(dirPath+"STF.dll");
      }


      Пробовали в си-стиле делать?

      Для wchar_t*
      ExpandedWrap disabled
        public static int connectDl(){
            return new DllUse().connectDll(dirPath+"STF.dll\0x00");
        }


      Добавлено
      В общем, попробую объяснить свою позицию. В яве строки (String) более правильные с точки зрения человека, то есть, имеется адрес начала строки, и длинна строки. В сях, ваш wchar_t* имеет адрес начала, но, не имеет длинны.

      Отсюда, чтобы узнать длину строки в яве, достаточно прочитать эту длину в области, недалеко от адреса начала массива данных (собственно, самой строки), как это сделано более подробно - это другой вопрос. Для того чтобы узнать длинну строки в сях, введено такое понятие как терминатор строки, суть в следующем, обращаемся по адресу начала строки, далее, смещаем курсор, читая по одному (или несколько) байту до тех пор, пока не натолкнёмся на \0x00 терминатор (если читаем по несколько байт, скорее всего, достаточно того случая когда первый байт 0x00, но, могу ошибаться, и важно заполнить весь буфер \0x00 терминаторами).

      Вот и получается - вы в памяти резервируете явой строку dirPath+"libDllUse.dll", сишный код начинает искать конец этой строки, и пропускает курсор далеко за вашу строку, пока где то там, в памяти не наткнётся на \0x00 терминатор.
      Сообщение отредактировано: VisualProg -
        Цитата Anka-BOIN @
        jni прослойка libDllUse.с
        ExpandedWrap disabled
          static HINSTANCE mod;
          JNIEXPORT jint JNICALL Java_DllUse_connectDll
          (JNIEnv *env, jobject obj, jstring path)
          {  
              const char* ipstr=(*env)->GetStringUTFChars(env, path, NULL);
           
              wprintf((const wchar_t *)ipstr);  // стр1
           
              mod=LoadLibrary((const wchar_t *)ipstr);
              (*env)->ReleaseStringUTFChars(env, path, ipstr1);
              if (mod == NULL) {  return -1;}
              return 1;
          }

        После вызова функция connectDl() возвращает -1, следовательно подключение не происходит. стр1 выводит:
        ..путь..\STF.dll_Разнообразная_Абракадабра

        Я, может, чего-то не понимаю в C, но каким магическим образом, по-твоему, массив UTF-8 байт (char* ipstr), должен преобразоваться в массив wchar_t* обычным тайпкастом?

        https://maxammann.github.io/2015/01/11/c-utf8-to-wchar/

        Добавлено
        Цитата VisualProg @
        В общем, попробую объяснить свою позицию. В яве строки (String) более правильные с точки зрения человека, то есть, имеется адрес начала строки, и длинна строки. В сях, ваш wchar_t* имеет адрес начала, но, не имеет длинны.

        Отсюда, чтобы узнать длину строки в яве, достаточно прочитать эту длину в области, недалеко от адреса начала массива данных (собственно, самой строки), как это сделано более подробно - это другой вопрос. Для того чтобы узнать длинну строки в сях, введено такое понятие как терминатор строки, суть в следующем, обращаемся по адресу начала строки, далее, смещаем курсор, читая по одному (или несколько) байту до тех пор, пока не натолкнёмся на \0x00 терминатор (если читаем по несколько байт, скорее всего, достаточно того случая когда первый байт 0x00, но, могу ошибаться, и важно заполнить весь буфер \0x00 терминаторами).

        Вот и получается - вы в памяти резервируете явой строку dirPath+"libDllUse.dll", сишный код начинает искать конец этой строки, и пропускает курсор далеко за вашу строку, пока где то там, в памяти не наткнётся на \0x00 терминатор.


        Судя по этой информации:
        Цитата
        UTF-8 strings are always terminated with the '\0' character, whereas Unicode strings are not. To find out how many bytes are needed to represent a jstring in the UTF-8 format, JNI programmers can either call the ANSI C function strlen on the result of GetStringUTFChars, or call the JNI function GetStringUTFLength on the jstring reference directly.

        https://stackoverflow.com/a/16700206
        дело не в '\0'.
          Цитата korvin @
          Я, может, чего-то не понимаю в C, но каким магическим образом, по-твоему, массив UTF-8 байт (char* ipstr), должен преобразоваться в массив wchar_t* обычным тайпкастом?


          А в чём может быть проблема? Хотите сказать, что в wchar_t байты с младшими и старшими разрядами перевёрнуты?
          Сообщение отредактировано: VisualProg -
            Цитата VisualProg @
            А в чём может быть проблема? Хотите сказать, что в wchar_t байты с младшими и старшими разрядами перевёрнуты?

            Хочу сказать, что UTF-8 — мультибайтовая кодировка: один code point может быть представлен как одним, так и шестью байтами. Да что там говорить, даже если взять любую однобайтовую кодировку, каким образом, по-твоему, простой сишный тайпкаст должен преобразовать массив char'ов в массив wchar_t'ов, которые, в винде представляют двухбайтный UTF-16, а в *nix'ах могут и UTF-32? Ну и byte-order, конечно, тоже.

            Например:
            ExpandedWrap disabled
              import java.nio.charset.Charset;
              import java.nio.charset.StandardCharsets;
              import java.util.Arrays;
              import java.util.function.Function;
              import java.util.stream.Stream;
               
              public final class Charsets {
               
                  public static void main(String[] args) {
                      printBytes("Hello");
                      printBytes("Привет");
                      printBytes("こんにちは");
                  }
               
                  private static void printBytes(String s) {
                      Stream.of(StandardCharsets.US_ASCII, StandardCharsets.UTF_8, StandardCharsets.UTF_16)
                              .map(showBytes(s))
                              .forEach(System.out::println);
                      System.out.println();
                  }
               
                  private static Function<Charset, String> showBytes(String s) {
                      return cs -> String.format("%s in %10s = %s", s, cs, Arrays.toString(s.getBytes(cs)));
                  }
              }

            получаем:
            ExpandedWrap disabled
              Hello in   US-ASCII = [72, 101, 108, 108, 111]
              Hello in      UTF-8 = [72, 101, 108, 108, 111]
              Hello in     UTF-16 = [-2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111]
               
              Привет in   US-ASCII = [63, 63, 63, 63, 63, 63]
              Привет in      UTF-8 = [-48, -97, -47, -128, -48, -72, -48, -78, -48, -75, -47, -126]
              Привет in     UTF-16 = [-2, -1, 4, 31, 4, 64, 4, 56, 4, 50, 4, 53, 4, 66]
               
              こんにちは in   US-ASCII = [63, 63, 63, 63, 63]
              こんにちは in      UTF-8 = [-29, -127, -109, -29, -126, -109, -29, -127, -85, -29, -127, -95, -29, -127, -81]
              こんにちは in     UTF-16 = [-2, -1, 48, 83, 48, -109, 48, 107, 48, 97, 48, 111]


            Вот теперь представь, что у тебя char* utf8 = [72, 101, 108, 108, 111], а ты его кастишь к wchar_t* utf16 = (wchar_t*) utf8, берёшь utf16[0] и получаешь, например (в зависимости от byte order), (72<<8)+101 = 18533. Какой это символ в Unicode? Дальше читаешь utf16[1], получаешь (108<<8)+108, потом utf16[2] -> (111<<8)+0 (тот самый '\0'), а дальше выход за пределы массива, UB, segfault и всё такое. Да, ты прав, что '\0' пропускается, но причины другие.

            Вот попробуй:
            ExpandedWrap disabled
              #include <wchar.h>
              #include <stdio.h>
               
              int main(void) {
                  char* s = "Hello";
                  printf("%s\n", s);
                  wprintf((const wchar_t*) s);
                  printf("\n--------\n");
                  const wchar_t* ws = (const wchar_t*) s;
                  for (int i = 0; i < 5; i++) {
                      printf("%d ", ws[i]);
                  }
                  printf("\n--------\n");
                  return 0;
              }


            Я удивлён, что у него вообще wprintf что-то напечатал внятное. Ideone, с 4-хбайтным wchar_t:
            ExpandedWrap disabled
              Hello
               
              --------
              1819043144 755630191 757935405 2960685 2122789
              --------
            Сообщение отредактировано: korvin -
              Цитата korvin @
              wprintf((const wchar_t*) s);

              Скорее всего, я не правильно объяснился. Вот про что я имел ввиду.

              ExpandedWrap disabled
                    #include <wchar.h>
                    #include <stdio.h>
                    
                    int main(void) {
                    
                        char* s1 = "\0H\0e\0l\0l\0o";
                        char* s2 = "H\0e\0l\0l\0o\0";
                    
                        wprintf((const wchar_t*) s1);
                        wprintf((const wchar_t*) s2);
                    
                        printf("\n--------\n");
                        const wchar_t* ws1 = (const wchar_t*) s1;
                        for (int i = 0; i < 5; i++) {
                            printf("%d ", ws1[i]);
                        }
                        printf("\n");
                        const wchar_t* ws2 = (const wchar_t*) s2;
                        for (int i = 0; i < 5; i++) {
                            printf("%d ", ws2[i]);
                        }
                        printf("\n--------\n");
                        return 0;
                    }


              Я просто не поверю что ява кодирует символы одним байтом)
              И на этом примере вижу, что действительно ничего не получится, потому что я даже не подозревал что wchar_t 32 битный и использует 4 байта.
              Сообщение отредактировано: VisualProg -
                Цитата VisualProg @
                Скорее всего, я не правильно объяснился. Вот про что я имел ввиду.

                Мне из этого не понятно, что ты имел в виду.

                Цитата VisualProg @
                Я просто не поверю что ява кодирует символы одним байтом)

                Какая ява? java.lang.String хранит массив char (Java'вских char'ов, не Сишных), которые двухбайтный UTF-16.
                JNI'шный метод GetStringUTFChars, которым пользуется ТС, согласно документации на сайте, возврашает массив байтов (сишных char'ов) UTF-8, которая мультибайтовая, т.е. символы (юникодные code point'ы) там кодируются последовательностями от 1 до 6 байт, в зависимости от символа. Так, например, символы из ASCII кодируются одним байтом, символы кириллицы — двумя. В википедии есть же схема, ну. Сишный же wchar_t имеет размер (в винде) — 2 байта, следовательно массив UTF-8 char и массив UTF-16 wchar_t — не совместимы и кастить их нельзя, я же показал в какие последовательности байт преобразуются стринги, возьми UTF-8, подставь в char* s1 = …, и посмотри, что получится в wchar_t* ws1 = (wchar_t*) ws1;

                Цитата VisualProg @
                даже не подозревал что wchar_t 32 битный и использует 4 байта.

                Его размер зависит от платформы (ОС) и, наверное, ещё чего-то. На MSDN можно найти указание, что в винде он 16-битный.
                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                0 пользователей:


                Рейтинг@Mail.ru
                [ Script execution time: 0,0373 ]   [ 15 queries used ]   [ Generated: 19.03.24, 07:16 GMT ]