所以開始把原本的python win32的程式改一改
只是看著使用的python版本是3.5.3
想說3.7.1都出來了,不然更新一下最新版好了
.......
沒錯,狀況就這樣發生了
在傳遞filter_string給OPENFILENAME的Structure時
跳出了ValueError: embedded null character
上網開始資料後,很快地就發現是python已知的Issue
Issue32745:ctypes string pointer fields should accept embedded null characters
當下看到,第一時間就覺得自己無法處理
只好再換回3.5.3版運作
直到上網討論後,有網友給了新方向
再試!.....唉~~又失敗
再看看線上手冊的ctypes說明
!
好像有招了
簡單地說,就是利用create_unicode_buffer建立字元陣列
再轉換類型為c_wchar_p就可解決
不過還是有些小細節要處理
詳細說明如下
在線上手冊介紹ctypes的章節裡
python使用create_string_buffer時
可以建立一串空字串,同時不被舉出ValueError
>>> from ctypes import * >>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes >>> print(sizeof(p), repr(p.raw)) 3 b'\x00\x00\x00' >>> p = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated string >>> print(sizeof(p), repr(p.raw)) 6 b'Hello\x00' >>> print(repr(p.value)) b'Hello' >>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer >>> print(sizeof(p), repr(p.raw)) 10 b'Hello\x00\x00\x00\x00\x00' >>> p.value = b"Hi" >>> print(sizeof(p), repr(p.raw)) 10 b'Hi\x00lo\x00\x00\x00\x00\x00' >>>所以使用同類型的create_unicode_buffer後也會可以處理空字元
這樣第一步算是完成了
接著第二步就是型別轉換
因為如果使用下面的程式碼時
>>> from ctypes import * >>> class TestStruct(Structure): # create a 3 byte buffer, initialized to NUL bytes ... _fields_ =[("unicode", c_wchar_p)] ... >>> t = TestStruct() >>> u = create_unicode_buffer("foo\0bar", 7) >>> t.unicode = u Traceback (most recent call last): File "", line 1, in TypeError: incompatible types, c_wchar_Array_7 instance instead of c_wchar_p instance >>>很明顯地兩個不能互傳
所以要用cast()來轉換
>>> t.unicode = cast(u, c_wchar_p) >>> print(t.unicode) 'foo' >>>不過這看起來有點怕怕的
畢竟後面的資料看來都不見了
然後unicode的Array又沒有像c_char的陣列可以看raw資訊
所以到底有沒有傳過去呢?
實際丟字串"PDF檔案(*.PDF)\0*.pdf\0其它檔案(*.*)\0*.*\0"
打開程式,看起來是沒問題,不過怎麼有點怪怪的...
可以看到後面多掛了兩串亂碼資料在
當下蠻傻眼的
想了一陣子後就懂了
因為c_wchar_p是指標,而windows api要知道c_wchar_p中止字串資料的結尾,需要2個空字元才行
而我在建立c_wchar_Array時,用的長度只有整個字串的長度
filter_string = "PDF檔案(*.PDF)\0*.pdf\0其它檔案(*.*)\0*.*\0" ofn = OPENFILENAME() temp_str = create_unicode_buffer(filter_string, len(filter_string)) ofn.lpstrFilter = cast(temp_str, LPCWSTR)所以在記憶體裡的狀況會是
"PDF檔案(*.PDF)\0*.pdf\0其它檔案(*.*)\0*.*\0亂碼資料\0亂碼資料\0亂碼資料\0亂碼資料\0\0"
多讀了兩段
如果建立字串陣列時,將長度加一之後,在記憶體裡就會變成
"PDF檔案(*.PDF)\0*.pdf\0其它檔案(*.*)\0*.*\0\0亂碼資料\0亂碼資料\0亂碼資料\0亂碼資料\0\0"
資料就會只讀到我們想要的位置
filter_string = "PDF檔案(*.PDF)\0*.pdf\0其它檔案(*.*)\0*.*\0" ofn = OPENFILENAME() temp_str = create_unicode_buffer(filter_string, len(filter_string)+1) ofn.lpstrFilter = cast(temp_str, LPCWSTR)
沒有留言:
張貼留言