ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2024年3月29日(金) 05:19

全ての表示時間は UTC+09:00 です




新しいトピックを投稿する  トピックへ返信する  [ 7 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2012年6月16日(土) 01:08 
オフライン

登録日時: 2009年3月29日(日) 15:45
記事: 106
度々申し訳ありません。

前回のプログラムを作成している途中で、また躓いてしまいました。

ツリー型のテキストエディタを作っていて、それの作業ファイルをアーカイブにしようと思い、
以下のような構造でファイルを書き込んでいこうと考えました。

[ツリーのノードの種類(ルート、親、子など)] \n [ノードのテキスト] \n [ノードの内容のバイト数] \n [ノードの内容(テキストデータ)]\n
※\nは特殊文字(Ex"\n")のことです
※データは、0\nTitle\n3\nAAA\n........のように続きます


ここで、ノードのテキストを取得した時、なぜかデータにひどくノイズが入ります。

ソフトの画像(これの「ノードのタイトル」という文字を保存したい)

余計な文字が入る(取得したバッファをMessageBox関数で表示)

この部分のプログラム
コード:
'ツリー名
Dim itm As TVITEM
Dim TreeName[256] As Byte

itm.mask = TVIF_TEXT
itm.pszText = TreeName
itm.cchTextMax = 256
itm.hItem = hHandle

SendMessage(hTree,TVM_GETITEM,0,VarPtr(itm) As LPARAM)	'取得

'書き込むデータを作成
buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))
lstrcat(buffer,TreeName)
lstrcat(buffer,Ex"\n")

'wsprintf(buffer,Ex"%s\n",TreeName)

'書き込み
If WriteFile(hFile,buffer,lstrlen(TreeName) + lstrlen(Ex"\n"),VarPtr(WrittenByte),ByVal NULL)=FALSE Then
	MessageBox(hMainWnd,"ツリー名の書き込みに失敗しました","Error",MB_OK or MB_ICONWARNING)
	Exit For
End If
free(buffer)
※lstrlen(TreeName) + Len(Ex"\n")をMessageBox関数で表示すると、正当なバイト数が返されています
※wsprintfで最初にやっていましたが、出来なかったので方法を変えました。が、出来ませんでした。
※たまに、Heap block at ○○ modified at ×× past requested size of △と出ます(メモリが足り無い?)
※たまに、Invalid address specified to RtlFreeHeap(○○,☓☓ )と出ます(変なところに書き込まれている?)



こういうことをするのが初めてで、ものすごく長いコードになったため、一部分を抜粋して書かせて頂きました。
同様のコードをコピペして、 ノードの内容のバイト数、[ノードの内容(テキストデータ)の部分も作ったので同じようなエラーになります。

何かお分かりになられた方、いらっしゃいましたらご教授ください。
情報が足りなければ、かなり汚いコードにはなりますが記載させて頂きます。
よろしくお願いいたします。

_________________
↓個人的ソフト置き場
http://www.software.jpn.org/
↓萌えゲー製作とかしていたい
http://www.holygate.jpn.org/


通報する
ページトップ
投稿記事Posted: 2012年6月16日(土) 21:31 
オフライン

登録日時: 2006年2月05日(日) 17:10
記事: 215
お住まい: 東京都
下記のソースコード一目みて不思議に思いました。

buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))
lstrcat(buffer,TreeName)
lstrcat(buffer,Ex"\n")

というのはソースコードをみるとTreeNameにデータがまったく設定されていません。

lstrlen(TreeName) でOKですか?
lstrlen(TreeName)は上記のソースコードだと常時0となりますが?

ご確認願います。
もし見当違いだったらごめんなさい。
よろしくお願いします。


通報する
ページトップ
投稿記事Posted: 2012年6月17日(日) 04:05 
オフライン

登録日時: 2009年3月29日(日) 15:45
記事: 106
たかせ様
ご回答ありがとうございます。
引用:
buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))
lstrcat(buffer,TreeName)
lstrcat(buffer,Ex"\n")

というのはソースコードをみるとTreeNameにデータがまったく設定されていません。
これは、
コード:
Dim TreeName[256] As Byte

itm.mask = TVIF_TEXT
itm.pszText = TreeName
itm.cchTextMax = 256
itm.hItem = hHandle

SendMessage(hTree,TVM_GETITEM,0,VarPtr(itm) As LPARAM)
ここで、ノードのツリー名の値を取り込んでいます。
hTree=GetDlgItemText(hMainWnd,Treeview1)
のことです。

よろしくお願いいたします

_________________
↓個人的ソフト置き場
http://www.software.jpn.org/
↓萌えゲー製作とかしていたい
http://www.holygate.jpn.org/


通報する
ページトップ
 記事の件名: どうでしょう
投稿記事Posted: 2012年6月17日(日) 19:50 
'書き込むデータを作成
① buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))
② Exit For
③ free(buffer)

②から Forで繰り返し処理をされているのかなと思いますが
③で開放したあと①でメモリ確保をしていますが
callocの説明に「malloc関数とは異なり、この関数ではメモリの0クリアを行います。」
とあり、mallocでは何かのデータが入っているかもしれないのが原因の1つではないかとおもったりしました。
①より 要るかいらないか分かりませんが文字列の最後は「0」で終わるようにしましょう的な事を
どっかで聞きかじっているので
buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))

buffer=calloc(lstrlen(TreeName) + Len(Ex"\n") +1 )
のほうが安全ぽいなぁと思いました。

独学だけなので頓珍漢な返答でしたら
やさしさで全スルーしてあげてください。


通報する
ページトップ
   
投稿記事Posted: 2012年6月17日(日) 21:29 
オフライン

登録日時: 2009年3月29日(日) 15:45
記事: 106
kobo様
ご回答ありがとうございます。
私も独学なので、アホなことばかりしております><
引用:
②から Forで繰り返し処理をされているのかなと思いますが
③で開放したあと①でメモリ確保をしていますが
callocの説明に「malloc関数とは異なり、この関数ではメモリの0クリアを行います。」
とあり、mallocでは何かのデータが入っているかもしれないのが原因の1つではないかとおもったりしました。
①より 要るかいらないか分かりませんが文字列の最後は「0」で終わるようにしましょう的な事を
どっかで聞きかじっているので
buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))

buffer=calloc(lstrlen(TreeName) + Len(Ex"\n") +1 )
のほうが安全ぽいなぁと思いました。
上の画像をご覧いただければ見えやすくなると思いますが、
ツリービューをもちいたテキストエディタで、内容をアーカイブ保存しようとしていますので、
Forループでノードの内容すべてを保存しようとしております。

mallocもcallocも試したのですが、同じだったのです……
あ!NULL文字!!
確かに+1がいるかも知れません。
後でABのテキスト見なおしてみます!!


とりあえず、いじり回って気がついたことと解決と疑問と続きの質問をば。


まず、私の
コード:
buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))
lstrcat(buffer,TreeName)
lstrcat(buffer,Ex"\n") 
ですが、連結かつ連結!となっています。
そりゃゴミつくわね……
コード:
buffer=malloc(lstrlen(TreeName) + Len(Ex"\n"))
lstrcpy(buffer,TreeName)
lstrcat(buffer,Ex"\n") 
とするのが正解でした。

しかし、確保しているメモリ以上に連結してエラーが出なかったのはちょっと困りましたね……
もしかして、
引用:
※たまに、Heap block at ○○ modified at ×× past requested size of △と出ます(メモリが足り無い?)
※たまに、Invalid address specified to RtlFreeHeap(○○,☓☓ )と出ます(変なところに書き込まれている?)
これがそのエラーだったのかな……?

とりあえず、これで、おそらく、ファイルの保存はできたと思います。


保存は出来ました。
しかし、デバグ時に必ず、
Heap block at ○○ modified at ×× past requested size of △
が連発します。

なので、size of △の△をmallocするときに加えました。

エラーは消えますが、もちろん値が変わった時(例:△=3だった時にmallocで3を加えた。今度は△=6だとエラーが出る)に、
同じエラーが出るので、ちょっと腹が立ち、*2にするとエラーも出ず、値もしっかりファイルに保存されました。
何故*2にしたら保存されるのかが謎です。

あと、malloc、calloc関数ですが、これは上書きされるのかなぁ……?
みたいな疑問も。

Dim a As *Byte
a=malloc(10)
lstrcpy(a,"test data")
a=calloc(11)
lstrcpy(a,"test dataA")
free(a)
のようなプログラムだと、どうなっているのかな……みたいな。
メモリAが確保されたまま、違うメモリBを確保し、メモリBだけ解放されてる……
となっているのでしょうか。
……そうならないためのreallocなのかなぁ



さて、再度質問させて頂きます。
書き込んだデータを読み込むと、先と同様、いらぬ文字が付加されます。

保存したデータ

読み込んだデータ

ツリーのノードを読み込む処理は、以下の様な感じです。
コード:
'ツリー名を確認
ReadByte=SearchOneTextPointFormFile(hFile,Ex"\n",StartPoint)
If ReadByte=0 Then
	Exit Do
End If

TreeName=calloc(ReadByte)

'ファイルポインタを動かす
SetFilePointer(hFile,StartPoint,0,FILE_BEGIN)

If ReadFile(hFile,TreeName,ReadByte,VarPtr(ReadFileLen),ByVal 0)=FALSE Then
	MessageBox(hMainWnd,Ex"ファイルの値が読み出せません\r\nError:TreeName","Error",MB_OK or MB_ICONWARNING)
	free(NodeInfo)
	free(TreeName)
	Exit Do
End If


'検索開始ポイントをずらす
StartPoint=StartPoint+ReadByte+1
SearchOneTextPointFormFile関数は以下のように定義しています。
コード:
Function SearchOneTextPointFormFile(hFile As HFILE,Text As BytePtr,SearchStartPoint As Long) As Long
	Dim temp[0] As Byte
	Dim Count As Long
	Dim ReadFileLen As DWord
	Dim SearchPointLog As Long

	'ファイルのポインタの位置を記録
	SearchPointLog=SearchStartPoint

	'ポインタを動かす
	SetFilePointer(hFile,SearchStartPoint,0,FILE_BEGIN)

	Do
		If ReadFile(hFile,temp,1,VarPtr(ReadFileLen),ByVal 0)=FALSE or ReadFileLen=0 Then
			Exit Do
		End If

		If lstrcmp(temp,Text)=0 Then
			SearchOneTextPointFormFile=Count

			'ポインタを戻す
			SetFilePointer(hFile,SearchPointLog,0,FILE_BEGIN)
			Exit Function
		End If
		
		Count++
	Loop

	SearchOneTextPointFormFile=0
	
	'ポインタを戻す
	SetFilePointer(hFile,SearchPointLog,0,FILE_BEGIN)

End Function
よろしくお願いいたします。

_________________
↓個人的ソフト置き場
http://www.software.jpn.org/
↓萌えゲー製作とかしていたい
http://www.holygate.jpn.org/


最後に編集したユーザー 水波形 [ 2012年6月23日(土) 23:21 ], 累計 1 回

通報する
ページトップ
投稿記事Posted: 2012年6月18日(月) 19:44 
オフライン

登録日時: 2006年2月05日(日) 17:10
記事: 215
お住まい: 東京都
ソースコード大雑把に見ましたが確認したい点があります。

ReadByte=SearchOneTextPointFormFile(hFile,Ex"\n",StartPoint)を実行するとたとえばノード名が"NoDe01\r\n"のときReadByteに8が設定されますよね?

これは私の勝手な想像ですが、
ツリー名を格納するエリアが8バイト分初期化して確保されます。
TreeName=calloc(ReadByte)
そして8バイト分ファイルから読み込まれます。
If ReadFile(hFile,TreeName,ReadByte,VarPtr(ReadFileLen),ByVal 0)=FALSE Then
MessageBox(hMainWnd,Ex"ファイルの値が読み出せません\r\nError:TreeName","Error",MB_OK or MB_ICONWARNING)
free(NodeInfo)
free(TreeName)
Exit Do
End If
しかしこれでは文字列の終端を示すNULL文字(0)が設定されていません。
なので”いらぬ文字”が付加される可能性があると思います。
そこで
TreeName=calloc(ReadByte)を
TreeName=calloc(ReadByte + 1)に変えてみてはいかがでしょうか?
つまりNULL文字(0)の分1バイト多く確保します。
ちなみにmallocだと
TreeName=malloc(ReadByte + 1)
ReadFile(hFile,TreeName,ReadByte,VarPtr(ReadFileLen),ByVal 0)
TreeName(ReadByte)=0
となります。

念のためご確認願います。
よろしくお願いします。


通報する
ページトップ
投稿記事Posted: 2012年6月20日(水) 01:46 
オフライン

登録日時: 2009年3月29日(日) 15:45
記事: 106
たかせ様

ご回答ありがとうございます。
1Byte分多く確保すると、きちんと取得することができました!
ありがとうございました!!

また質問させていただくとは思いますが、
その時はよろしくお願い致します。
今回は本当にありがとうございました!

_________________
↓個人的ソフト置き場
http://www.software.jpn.org/
↓萌えゲー製作とかしていたい
http://www.holygate.jpn.org/


通報する
ページトップ
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 7 件の記事 ] 

全ての表示時間は UTC+09:00 です


オンラインデータ

このフォーラムを閲覧中のユーザー: Baidu [Spider], Bing [Bot] & ゲスト[18人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
cron
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by ocean