クリップボードと文字列

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
BingoMan
記事: 36
登録日時: 2005年7月17日(日) 09:36
お住まい: 千葉県松戸市

クリップボードと文字列

#1 投稿記事 by BingoMan »

コード: 全て選択

Dim X As String
X="A"
OpenClipboard(0)
EmptyClipboard()
SetClipboardData(CF_TEXT,VarPtr(X))
CloseClipboard()
これではクリップボードの中身が空のままのようです。何が間違っているのでしょうか?
淡幻星

Re: クリップボードと文字列

#2 投稿記事 by 淡幻星 »

クリップボードに貼り付けた(内容を指し示す)ポインタは、
プログラムが終了後も有効である必要があります。

しかし、Dim宣言によって確保されたバッファは、
プログラム終了と同時にすべて開放されます(無効になる)。
よってそのバッファのポインタも無効になります。

したがって、クリップボードに渡すポインタ(が表すバッファ)は、
GlobalAlloc()を利用して別途確保する必要があります。

具体的にはこんな感じです。

コード: 全て選択


Dim X As String 
Dim retAns As Long
X="A" 
retAns = WsSetClipStr( StrPtr( X ) )

End


'クリップボードに文字列を貼り付ける。
Function WsSetClipStr( pBuffer As BytePtr ) As Long
	Dim nSize As Long
	Dim hGlobalMem As DWord
	Dim pGlobalMemForClipText As BytePtr

	'クリップボードを開く
	While ( OpenClipboard(0)=FALSE )
		Sleep (1)
	Wend

	'クリップボードを空にする。
	EmptyClipboard()

	'貼り付ける文字列の大きさを得て、クリップボード用のバッファを確保
	nSize = lstrlen( pBuffer )
	hGlobalMem = GlobalAlloc( GHND Or GMEM_SHARE, nSize + 1 )
	pGlobalMemForClipText = GlobalLock(hGlobalMem)
		pGlobalMemForClipText = lstrcpy( pGlobalMemForClipText, pBuffer )
	GlobalUnlock( hGlobalMem )
	SetClipboardData( CF_TEXT, hGlobalMem )

	'クリップボードを閉じる
	CloseClipboard()

	WsSetClipStr = TRUE
EndFunction

蛇足ですが、クリップボード用のバッファは移動可能メモリである必要が
ある(・・・ほんとか?)ので、GHNDを指定して、操作時はGlobalLock()で
メモリオブジェクトをロックしておく必要があります。


参考までに、7さんがクリップボードの文字列操作用のクラスを作られています。
http://www.discoversoft.net/forum/viewtopic.php?t=54
もしVer4.xを御利用でしたら、そちらを使うのが楽かも知れません。
(私はVer3.x派なもので^^;)

コード: 全て選択

BingoMan
記事: 36
登録日時: 2005年7月17日(日) 09:36
お住まい: 千葉県松戸市

#3 投稿記事 by BingoMan »

淡幻星様のプログラムでうまくいきました。ありがとうございます。
ただ、ひとつ気になったのが

コード: 全て選択

hGlobalMem = GlobalAlloc( GHND Or GMEM_SHARE, nSize + 1 )
ここで、GMEM_SHAREという定数がヘルプファイルに載っていなかったのですが、
   GHND Or GMEM_SHARE

   GHND
だけにしても正常に動作しました。GMEM_SHAREという定数はどんなものなのでしょうか。
また、Dim宣言によって確保されたものではクリップボードに貼り付けてもプログラム終了と同時に無効になってしまうとのことですが、次のプログラムは正常に動作しました。

コード: 全て選択

   Dim hDC As Long
   Dim hBmp As Long
   Dim hOrgDC As Long

   hOrgDC=GetDC(0)
   hDC=CreateCompatibleDC(hOrgDC)
   hBmp=CreateCompatibleBitmap(hOrgDC,100,100)
   SelectObject(hDC,hBmp)
   ReleaseDC(0,hOrgDC)

   '---描画処理---

   OpenClipboard(0)
   EmptyClipboard()
   SetClipboardData(CF_BITMAP,hBmp)
   CloseClipboard()
   DeleteDC(hDC)
   DeleteObject(hBmp)
文字列の場合とビットマップの場合とではクリップボードの使い方が異なるのでしょうか。
淡幻星
記事: 183
登録日時: 2005年7月19日(火) 07:02
お住まい: 宮城県
連絡する:

クリップボードに対してのDeleteObject()は無効?

#4 投稿記事 by 淡幻星 »

>GHNDだけにしても正常に動作しました。
>GMEM_SHAREという定数はどんなものなのでしょうか。
実は私も GMEM_SHARE は意味もわからず使ってました(サンプルプログラム丸写し/爆)。
ちゃんと調べてみたところ、今時の(正確にはWin95以降?)のWindosであれば、 GHND のみで良いみたいです。私の見たサンプルでは、Windows 3.xやそれ以前との互換性のために GHND Or GMEM_SHARE としてあったみたいです。
ちなみに、
GMEM_SHARE
ダイナミックデータエクスチェンジ (DDE) 対話のためにDDE 関数が使用するメモリを確保します。Windows 3.x とは異なり、このメモリはグローバルには共有されませんが互換性のために使用できます。
だそうです。spi_system.sbp 内で定義されています。
DDE 関数は、ActiveX の前世の前世とでも思ってください。


>文字列の場合とビットマップの場合とでは
>クリップボードの使い方が異なるのでしょうか。
一緒です(そのはず)。・・・が、おかしいですね。
DeleteObject( hBmp )した時点で消えるのが普通だと思うんですが。
考えられる要因としては、APIを呼び出しているが故かもしれません。
hBmp の指し示すバッファ自体はプログラム側としてはノータッチ(終了時にも開放はされない)ですよね。なのでDeleteObject(hBmp) で明示的に開放してやる必要があるんですが、これはAPIです。よってシステムと強く関連している可能性があります。SetClipboardData( CF_BITMAP, hBmp )をした時点で、hBmp の所有権はシステムに移るので、それゆえにDeleteObject()をしても開放されず、有効のままクリップボードに残るのかもしれません。


デバイスコンテキスト周りは詳しくないので、間違っていたら、ごめんなさい。

そういえば、以前にも
最終行の「DeleteObject」なのですが、使用した方が良いのでしょうか?
私は、クリップボードの内容であり共有であるため削除してはいけないのでは?と思うのですが、この行を実行してもクリップボードの内容は消えません。
しかもDeleteObjectの戻り値が1になっているようです。
という記事(投稿者hiraさん)がありましたね。このときはこれに対するレスはありませんでしたが、詳しい方いらっしゃいましたら、ぜひお願いします。
まけイヌ
記事: 27
登録日時: 2005年7月03日(日) 10:37
お住まい: 愛知県岡崎市
連絡する:

Re: クリップボードに対してのDeleteObject()は無効?

#5 投稿記事 by まけイヌ »

> DeleteObject( hBmp )した時点で消えるのが普通だと思うんですが。
GetClipboardData関数(API)の説明を読む限りでは、
どうやらSetClipboardData関数(API)で受けたビットマップハンドルを元に、
グローバルなメモリの領域にコピーしているっぽいですね。
何故にビットマップだけやるのかは疑問ですが..

>
> 最終行の「DeleteObject」なのですが、使用した方が良いのでしょうか?
> 私は、クリップボードの内容であり共有であるため削除してはいけないのでは?と思うのですが、この行を実行してもクリップボードの内容は消えません。
> しかもDeleteObjectの戻り値が1になっているようです。
>
> という記事(投稿者hiraさん)がありましたね。このときはこれに対するレスはありませんでしたが、詳しい方いらっしゃいましたら、ぜひお願いします。
仕様では、1が返る事自体は問題ありません。
しっかりと削除されています。

が、DeleteObject関数(API)が内部で何をやっているか、ですね。
恐らくそのハンドルの指す場所以降のオブジェクトサイズ分の
メモリブロックを開放しているだけでしょう。
そうなると、たまたま同じアドレスにアクセスすると、
まだまだ見られたりするのかもしれませんね。
※質問内容がクリップボード周りなので、この回答はアテになりませんが..
# まけイヌ (losedog2)
# Home : http://www50.tok2.com/home/losedog2/
# Mail : losedog2@yahoo.co.jp
返信する