<html><head><style type='text/css'>p { margin: 0; }</style></head><body><div style='font-family: Times New Roman; font-size: 12pt; color: #000000'>Hello.<br>I uploaded the current patch to cr.openjdk:<br>http://cr.openjdk.java.net/~serb/8177951/webrev.00<br><br>I have tested the patch and here is my observation:<br> - The patch works for direct devices, but it looks like the same bug exists in Ports(also reproduced by your testcase), did you have a chance to look into this issue as well?<br> - jdk uses "warning-as-error" policy during the build, so currently there is a build failure, because of this warning:<br>        PLATFORM_API_WinOS_DirectSound.cpp(93) : warning C4267: 'initializing' : conversion from 'size_t' to 'DWORD', possible loss of data<br> - Note that the memory which is allocated by "new[]" should be deallocated by the "delete[]", but current fix use simple "delete".<br> - Can you please sign and submit the OCA[1], which will allow you to contribute to the openjdk?<br><br>[1] <a href="http://www.oracle.com/technetwork/community/oca-486395.html">http://www.oracle.com/technetwork/community/oca-486395.html</a><br><br><br>----- cqjjjzr@126.com wrote:
<br>> <div style="line-height:1.7;color:#000000;font-size:14px;font-family:Courier">> <div>Hello,</div><div>Please review this bug report: <a href="https://bugs.openjdk.java.net/browse/JDK-8177951" target="_blank">https://bugs.openjdk.java.net/browse/JDK-8177951</a> </div><div><br>> </div><div>A brief description of the issue:</div><div>In non-English Windows, the <i>DirectAudioDeviceProvider </i>can't work properly, <i>AudioSystem.getMixerInfo()[0].getName() </i>(or any other index, as long as the name of mixer contains non-ASCII characters)will return a corrupted string (all non-ASCII chars become messy codes).</div><div>The main reason is in native codes, we get a string in ANSI(platform-<span class="nui-menu-item-text">dependent</span>) charset. But in the code the string is just processed as a UTF-8 string. So the JVM encodes <b>ANSI</b> string by UTF-8 encoding.</div><div><br>> </div><div>Detailed description:</div><div>The performace of the bug is contained in the link above, I'll talk about the reason of the issue. All <span class="nui-menu-item-text">research</span> below are based on OpenJDK 9, but I think OpenJDK 8 is also applicable.</div><div><br>> </div><div>In <i><u>jdk/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_DirectSound.cpp</u></i>, Function <i>DS_GetDesc_Enum</i>, Line <b>236</b>, the name of the device is gotten(called by function <i>DirectSoundDeviceEnumerate</i>) from the OS, in <span style="color: rgb(255, 0, 0);"><b><i><u>ANSI</u></i></b></span> charset, in a <i>LPCSTR</i>. And you just copy the ANSI encoded string to the <i>DirectAudioDeviceDescription</i> struct. So let's look at the <i><u>jdk/src/java.desktop/share/native/libjsound/DirectAudioDeviceProvider.c</u></i>, Function <i>getDirectAudioDeviceDescription</i> and <i>Java_com_sun_media_sound_DirectAudioDeviceProvider_nNewDirectAudioDeviceInfo</i>, Line <b>48</b> and <b>98</b>, you called <i>NewStringUTF </i>function <span style="color: rgb(255, 0, 0);">with a ANSI encoded string. </span>So we got a <b>UTF-8 encoded ANSI string</b>. But obviously we need a <b>UTF-8 encoded Unicode String.</b></div><div><b><br>> </b></div><div>I wrote to Oracle but they can't reproduce the issue, so I went on fixing the bug by myself. I wrote a function to convert ANSI string to UTF-8 encoded Unicode string.</div><div><br>> </div><div>And I found a problem: In Multi-Byte compiling mode, <i>DirectSoundDeviceEnumerate </i>will call <i>DirectSoundDeviceEnumerateA </i>and it will present a ANSI string as the argument, but in Unicode mode, <i>DirectSoundDeviceEnumerate</i> calls <i>DirectSoundDeviceEnumerateW</i> which presents a UTF-8 encoded Unicode string! So I think it's necessary to check if the compiler is in Unicode mode(by checking UNICODE macro), and only convert the string when it's in Multi-Byte mode.</div><div><br>> </div><div>But, I don't have the debugging environment, I have problem configuring the compiler of OpenJDK. LINK : error LNK2001: unresolved external symbol _mainCRTStartup when executing ./configure script. So I can't test the validness of the patch. I'll be grateful if someone can help solve the configuring problem or test the patch for me. Even if you can compile the JDK with the patch is OK.</div><div>If you'd like to test the patch, you can test it with the first device from <i>DirectSoundDeviceEnumerate</i>, 'Primary Sound Driver'. Maybe you don't have Chinese font, I'll attach a picture to the correct output.</div><div><br>> </div><div>The patch is below and attached with the E-Mail. It's applicable for OpenJDK9, maybe 8 if you change it.</div><div><a href="https://imgur.com/a/6kgeU" target="_blank">https://imgur.com/a/6kgeU</a> </div><div>The code in the picture is just for generate a output, in the Unicode mode, so it's not applicable for JDK.</div><div><br>> </div><div><div>*** old/jdk/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_DirectSound.cpp<span class="Apple-tab-span" style="white-space:pre">       </span>2017-06-21 03:57:42.000000000 +0800</div><div>--- new/jdk/src/java.desktop/windows/native/libjsound/PLATFORM_API_WinOS_DirectSound.cpp<span class="Apple-tab-span" style="white-space:pre">  </span>2017-06-24 16:26:57.232247800 +0800</div><div>***************</div><div>*** 86,91 ****</div><div>--- 86,113 ----</div><div>  static UINT64 g_lastCacheRefreshTime = 0;</div><div>  static INT32 g_mixerCount = 0;</div><div>  </div><div>+ /// FIX BUG JDK-8177951: Convert ANSI encoded string to UTF-8 encoded string</div><div>+ LPCSTR ANSIToUTF8(const LPCSTR& lpAnsiStr)</div><div>+ {</div><div>+     // ANSI -> Unicode</div><div>+     DWORD dwAnsiLen = strlen(lpAnsiStr);</div><div>+     DWORD dwUnicodeLen = ::MultiByteToWideChar(CP_ACP, 0, lpAnsiStr, -1, NULL, 0);</div><div>+     LPWSTR lpUnicodeStr;</div><div>+     lpUnicodeStr = new WCHAR[dwUnicodeLen];</div><div>+     memset(lpUnicodeStr, 0, (dwUnicodeLen) * sizeof(WCHAR));</div><div>+     MultiByteToWideChar(CP_ACP, 0, lpAnsiStr, -1, lpUnicodeStr, dwUnicodeLen);</div><div>+ </div><div>+     // Unicode -> UTF8</div><div>+     LPSTR lpUTF8Str;</div><div>+     DWORD dwUTF8Len;</div><div>+     dwUTF8Len = WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, NULL, 0, NULL, NULL);</div><div>+     lpUTF8Str = new CHAR[dwUTF8Len];</div><div>+     memset(lpUTF8Str, 0, sizeof(CHAR) * (dwUTF8Len));</div><div>+     WideCharToMultiByte(CP_UTF8, 0, lpUnicodeStr, -1, lpUTF8Str, dwUTF8Len, NULL, NULL);</div><div>+     delete lpUnicodeStr;</div><div>+     return lpUTF8Str;</div><div>+ }</div><div>+ </div><div>  BOOL DS_lockCache() {</div><div>      /* dummy implementation for now, Java does locking */</div><div>      return TRUE;</div><div>***************</div><div>*** 233,239 ****</div><div>--- 255,267 ----</div><div>  </div><div>      INT32 cacheIndex = findCacheItemByGUID(lpGuid, g_audioDeviceCache[desc->deviceID].isSource);</div><div>      if (cacheIndex == desc->deviceID) {</div><div>+ #ifndef UNICODE</div><div>+         LPCSTR utf8EncodedName = ANSIToUTF8(lpstrDescription);</div><div>+         strncpy(desc->name, utf8EncodedName, DAUDIO_STRING_LENGTH);</div><div>+         delete utf8EncodedName;</div><div>+ #else</div><div>          strncpy(desc->name, lpstrDescription, DAUDIO_STRING_LENGTH);</div><div>+ #endif</div><div>          //strncpy(desc->description, lpstrModule, DAUDIO_STRING_LENGTH);</div><div>          desc->maxSimulLines = -1;</div><div>          /* do not continue enumeration */</div></div><div><br>> </div><div><br>> </div><div>Cheers,</div><div>Charlie Jiang</div></div><br>> <br>> <span title="neteasefooter"><p> </p></span></div></body></html>