こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

ExcelVBA:フォームの最小化ボタンを表示し、閉じるボタン「×」を消す方法

似たような質問をしたのですが、参考URLを元に自分で試してみたのですが、思うようにいかず、理解ができなかったので改めて質問します。
Excelのプログラムで右上にある閉じるボタン「×」を消して、なおかつ最小化ボタンを表示させるにはどのようにしたらよいのでしょうか?
解説付きでよろしくお願いします。

回答よろしくお願いします。

投稿日時 - 2007-12-09 10:10:15

QNo.3583195

すぐに回答ほしいです

質問者が選んだベストアンサー

タイトルバーで右クリックした場合などは閉じるボタンが有効化されるようです
これを捕捉するとなるとWM_NCLBUTONDOWNメッセージなどを処理する事になりそうです ・・・

投稿日時 - 2007-12-15 20:07:41

補足

そのようですね。

すいませんがそれも教えてくれませんか?

よろしくお願いします。

投稿日時 - 2007-12-15 21:01:00

お礼

ありがとうございました。

投稿日時 - 2007-12-19 15:06:59

このQ&Aは役に立ちましたか?

2人が「このQ&Aが役に立った」と投票しています

回答(8)

ANo.7

ん~ おかしいですね …
当方は WinXP SP2 + Office2003の環境ですが

一点修正を
コード側でEnableMenuItemの最後の引数のMF_DISABLEは MF_DISABLEDの間違いでした m(__)m

投稿日時 - 2007-12-14 18:27:22

お礼

すいません。

FindWindow("ThunderDFrame", "UserForm1")のところで"UserForm1"の名前を変えたので閉じるボタンが有効になっていたようです。そこを変更するのを忘れていました。
これで最小化ボタン有効、閉じるボタン無効に成功しました。

本当は分からないことがいっぱいあるのでお聞きしたいことがたくさんあるのですが、ここまで教えてもらっていただいて、さらにお聞きするのは大変申し訳ないので別の機会にします。
また、インターネットで自分でも調べられることは調べるようにしたいと思いました。

本当にありがとうございました。

投稿日時 - 2007-12-15 18:00:57

ANo.6

ごめんなさい m(__)m
DeleteMenuではうまくいかないようです
いろいろ実験していたので誤った情報を書き込んだようです

EnableMenuItemを使えばできるようです
標準モジュールに
Public Declare Function EnableMenuItem Lib "user32" _
(ByVal hMenu As Long, ByVal wIDEnableItem As Long, ByVal wEnable As Long) As Long
Public Const MF_DISABLED = &H2&
を追加します

Initializeイベントの DeleteMenuをEnableMenuItemに置き換えます

EnableMenuItem hSysMenu, SC_CLOSE, MF_BYCOMMAND or MF_DISABLE

といった具合です

投稿日時 - 2007-12-13 12:53:38

補足

追加したのですがやはり閉じるボタンだけ有効になってしまいます。

すいませんがよろしくお願いします。

投稿日時 - 2007-12-13 17:57:00

お礼

今更ですが、お礼の記載が大変遅くなり、申し訳ありません。

ありがとうございました。

投稿日時 - 2015-05-23 17:27:30

ANo.5

> では Integer ではなく Long ではないでしょうか
そのとおりです m(__)m
いろいろ回答していたので間違えました

Ano3の補足への回答ですが

DeleteMenuの第2引数が MF_BUCOMMANDになっていますが
これは MF_BYCOMMANDにしないとだめですね

こういった単純なスペルミスを防ぐためにも『変数宣言の強制』を設定しておいたほうが良いでしょう

VBEの画面で ツール > オプションの変数タブ
『変数の宣言を強制する』のチェックをつけておきます

既存のVBAコードについては
コードの先頭で
Option Explicit
といった1行を追加しておきます

このようにしておけば 宣言されていない変数(定数)は使用できなくなりますので タイプミスによるバグはほとんど回避が可能になります

ただ似たような変数名の打ち間違いまでは面倒見てくれませんので・・・

たとえば
dim Hen1, Hen2
hen1 = 1
' 本来 hen1を判断するところを Hen2とタイプした
if Hen2 = 1 then
  Hen2 = -1
  ' Hen3は宣言されていないのでチェックされる
  Hen3 = Hen2 * 2
end if

投稿日時 - 2007-12-12 12:26:58

補足

回答ありがとうございます。

なるほど。変数の宣言を強制した方が間違いが酸くなるんですね。勉強になります。

「MF_BYCOMMAND」に変更したのですがやはり、閉じるボタンが有効のままのようです。
「MF_BYCOMMAND」の値が「0」なのですがこれが原因なのでしょうか?
大変お手数ですがよろしくお願いします。

投稿日時 - 2007-12-12 23:15:58

お礼

今更ですが、お礼の記載が大変遅くなり、申し訳ありません。

ありがとうございました。

投稿日時 - 2015-05-23 17:27:40

ANo.4

横レス失礼します。。

> Public Declare Function GetSystemMenu Lib "user32" Alias "GetSystemMenuA" _
> (ByVal hWnd As String, _
> ByVal bRevert As Boolean) As Long

API の宣言文(API に渡す引数の型を含めて)は、API に関する知識が
深まるまで勝手に変えず、API ビューアや WEB などで紹介されている
とおり、そのままコピペして使いましょう。

 # これらの情報が絶対に間違っていないとは限りませんが...

Alias は意味もわからず付けてはダメです。また、GetSystemMenu の
第一引数 hWnd の型が String 型になってますが、Long 型の誤りかと。

参考URL:WinAPI Database for VB Programmer
http://www.winapi-database.com/

Declare Function GetSystemMenu Lib "user32.dll" ( _
  ByVal hwnd As Long, _
  ByVal bRevert As Long) As Long
Declare Function DeleteMenu Lib "user32.dll" ( _
  ByVal hMenu As Long, _
  ByVal nPosition As Long, _
  ByVal wFlags As Long) As Long

なお、#3 ご回答ですが、VB.Net 用のものではないかと思われます。VBA
では Integer ではなく Long ではないでしょうか。

投稿日時 - 2007-12-10 22:14:07

お礼

そうですね。まだはっきりと知識がないうちは変更せずそのまま使った方がいいようですね。

ありがとうございました。

投稿日時 - 2007-12-12 23:15:47

ANo.3

Declare宣言の関数名の最後にAをつけるのは ANSI/Unicodeの両方のAPIが存在する場合にどちらを使うのかを明確にするためです
FindWindowの参考URLの最後のほうに
『Unicode:Windows NT/2000 は Unicode 版と ANSI 版を実装』と明記されている場合に Aliasで指定します

GetSystemMenuはANSI/Unicodeの区別はありませんので

Declare Function GetSystemMenu Lib "user32.dll" _
(ByVal hWnd as Integer, ByVal bRevert as Integer) as Integer
といった具合の宣言で良いと思います

投稿日時 - 2007-12-10 21:21:35

補足

なるほど。
オーバーフローしてしまったのでLongに変えて作ってみました。
まだ分からないところがたくさんあるのですが、以下のように作ったところ、最小化ボタンは表示されたのですが「×」が使える状態なのですがどこが間違ってるのでしょうか?

標準モジュール
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Declare Function DrawMenuBar Lib "user32" _
(ByVal hWnd As Long) As Long

Public Declare Function GetSystemMenu Lib "user32.dll" _
(ByVal hWnd As Long, ByVal bRevert As Long) As Long

Public Declare Function DeleteMenu Lib "user32" _
(ByVal hMenu As Long, ByVal uPosition As Long, ByVal uFlags As Long) As Long

Public Const GWL_STYLE = (-16) 'ウィンドウスタイルを取得

Public Const WS_MINIMIZEBOX = &H20000 '最小化ボタン

Dim hSysMenu As Long

Public Const MF_BYCOMMAND = &H0&

Public Const SC_CLOSE = &HF060&

Initializeプロシージャ
Private Sub UserForm_Initialize()

Dim fRet As Long
Dim hWnd As Long
Dim fStyle As Long

UserForm1.Show vbModeless
hWnd = FindWindow("ThunderDFrame", "UserForm1")
fStyle = GetWindowLong(hWnd, GWL_STYLE)
fStyle = (fStyle Or WS_THICKFRAME Or WS_MINIMIZEBOX)
fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle)

hSysMenu = GetSystemMenu(hWnd, 0)
DeleteMenu hSysMenu, MF_BUCOMMAND, SC_CLOSE

fRet = DrawMenuBar(hWnd)
End Sub

度々すいません。

投稿日時 - 2007-12-10 22:19:24

お礼

今更ですが、お礼の記載が大変遅くなり、申し訳ありません。

ありがとうございました。

投稿日時 - 2015-05-23 17:27:11

ANo.2

ん~ インターネットがあるのですから調べてみましたか?
MicrosoftのMSDNサイトやWinAPIを開設したサイトはたくさんありますよ

『疑問部分を全て説明しろ』と言うのは無理があるのです

最初のほうの Declare文はWinAPIをVBで使えるようにする宣言です

FindWindowはどのような引数をとるのかを調べてみると
ウィンドウクラス名とウィンドウのタイトルの2つが必要だと解説されているはずです
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpwinui/html/_win32_findwindow.asp
これで取得したハンドルを使ってどのウィンドウに対する処理をするのかをWindowsに指示するわけです

『ThunderDFrame』はウィンドウクラス名です
『UserForm1』はユーザーフォームのCaptionプロパティに設定した文字列です

次のGetWindowLongですが タイトルバーに表示するタイトル名や最小化、最大化、閉じるのボタンなどのウィンドウの外観を変更するのに現在の設定を知る必要があるために使うAPIです
http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_getwindowlong.asp
GetWidowLongには引数nIndexに与えるデータによりさまざまなデータを取得可能なのです
今回は ウィンドウの外観なので GWL_STYLEを与えます

ここで取得したデータを使って希望するスタイルにするための演算を行います
fStyle = fStyle Or WS_MINIMIZEBOX
とします
もしも最大化ボタンが有効になっているのであれば そのスタイルを消去しないといけませんのでその場合は
fSyle = fStyle And ( Not WS_MAXIMIZEBOX )
といった具合にします

今度は外観を変更するためにWindowsに依頼するAPIを使う必要があります
これが SetWidowLongになります
http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_setwindowlong.asp
SetWindowLong/GetWindowLongは最初のSetとGetが違いと Getがデータを返すので引数は2つ Setはデータを設定するので3つの引数といった違いがあります
この2つが対になっていることが理解できるでしょうか

その参照URLコードには閉じるボタンの無効化は無いようです
閉じるボタンは ウィンドウの左肩にあるアイコンをクリックすると出る『移動』『サイズ変更』『最小化』『最大化』『閉じる』といったメニュを操作する事になります
これをするには
宣言区に以下の3行を追加します
Dim hSysMenu as Long
Const MF_BYCOMMAND = &H0&
Const SC_CLOSE = &HF060&

DrawMenuBarを呼び出す前に以下の2行を追加します
hSysMenu = GetSystemMenu( hWnd, 0 )
DeleteMenu hSysMenu, MF_BUCOMMAND, SC_CLOSE
といった具合に使います

http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_getsystemmenu.asp
http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_deletemenu.asp

ここまでやってからDrawMenuBarを呼び出して変更を反映させます
http://msdn.microsoft.com/library/ja/jpwinui/html/_win32_drawmenubar.asp

投稿日時 - 2007-12-10 00:10:23

補足

回答ありがとうございます。
プログラムにredfox63さんの言うとおりに追加したのですが、「エントリ GetSystemMenuAがDLLファイルuser32内に見つかりません」というエラーが出てしまったのですがこれはWinAPIをVBで使えるようにする宣言が間違ってしまったのでしょうか?以下の通りです。

Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long

Public Declare Function DrawMenuBar Lib "user32" _
(ByVal hWnd As Long) As Long

Public Declare Function GetSystemMenu Lib "user32" Alias "GetSystemMenuA" _
(ByVal hWnd As String, _
ByVal bRevert As Boolean) As Long

Public Declare Function DeleteMenu Lib "user32" Alias "DeleteMenuA" _
(ByVal hMenu As Long, _
ByVal uPosition As Long, _
ByVal uFlags As Long) As Long

新たに「GetSystemMenu」と「DeleteMenu」を追加したのですが、 「Public Declare Function DeleteMenu Lib "user32"」まではいいのですが、 その後ろに「Alias "DeleteMenuA"」をつけるのかつけないのか分かりません。データ型は調べたので合ってると思いますが。
よろしくお願いします。

投稿日時 - 2007-12-10 16:18:02

お礼

今更ですが、お礼の記載が大変遅くなり、申し訳ありません。

ありがとうございました。

投稿日時 - 2015-05-23 17:27:47

ANo.1

何処まで理解できていて 何が理解できていないのかを投稿しましょう

WinAPIの使い方をすべて説明するのは困難ですよ
『X』の非表示自体は無理です、無効状態になら出来ますが ・・・

WinAPIで操作するにはまずウィンドウハンドルを取得する必要があります ... FindWindow
次に 最小化、最大化、閉じるボタンの表示、非表示の設定をするにはウィンドウスタイルを変更するAPIを使います ... GetWindowLong/SetWindowLong

最小化、最大化は単独で表示、非表示の切り替えが可能です
閉じるは最小化、最大化、閉じるの3個セットで表示、非表示の切り替えになります

閉じるの無効化をするためにはそのウィンドウのシステムメニューを操作する必要があります ... GetSystemMenu/DeleteMenu/DrawMenuBar

投稿日時 - 2007-12-09 12:41:52

補足

回答ありがとうございます。
参考URLからコピーしたものなんですが、まず最初に、

標準モジュール
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long

Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long) As Long

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
(ByVal hWnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long

Public Declare Function DrawMenuBar Lib "user32" _
(ByVal hWnd As Long) As Long

この部分が何をしているのか分かりません。
それから、

標準モジュール
Public Const GWL_STYLE = (-16) 'ウィンドウスタイルを取得
Public Const WS_THICKFRAME = &H40000 'ウィンドウのサイズ変更
Public Const WS_MINIMIZEBOX = &H20000 '最小化ボタン
Public Const WS_MAXIMIZEBOX = &H10000 '最大化ボタン

この部分は恐らく「ウィンドウスタイルを取得」「最小化ボタン」が必要だとは分かります。あとの「ウィンドウのサイズ変更」「最大化ボタン」はこの場合は使用しないので必要ないと思います。

redfox63さんのおっしゃる「ウィンドウハンドルを取得する必要がある」というのは、

UserForm_Initializeプロシージャ
Dim fRet As Long
Dim hWnd As Long
Dim fStyle As Long

UserForm1.Show vbModeless 'ユーザーフォームを表示する
hWnd = FindWindow("ThunderDFrame", "UserForm1") 'ユーザーフォームのハンドルを取得する
fStyle = GetWindowLong(hWnd, GWL_STYLE) 'ウィンドウに関する情報を取得する
fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX) 'Min,Maxメニューボタンを付加する
fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle) 'ユーザーフォームに追加したボタンを設定する
fRet = DrawMenuBar(hWnd) 'ユーザーフォームのメニューバー外枠を再描画する

「hWnd = FindWindow("ThunderDFrame", "UserForm1")」この部分でしょうか?
一番上の「UserForm1.Show vbModeless 」はいいとして、まず、
「"ThunderDFrame"」の意味が分かりません。それと「"UserForm1"」はオブジェクト名でしょうか?

>次に 最小化、最大化、閉じるボタンの表示、非表示の設定をするにはウィンドウスタイルを変更するAPIを使います ...

これは、「fStyle = GetWindowLong(hWnd, GWL_STYLE)」この部分でしょうか?ここでも何をしているのか分かりません。

>閉じるの無効化をするためにはそのウィンドウのシステムメニューを操作する必要があります

これは、どこの部分を指すのでしょうか?

「fStyle = (fStyle Or WS_THICKFRAME Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX) 」この部分は説明の通りなので「Or WS_MINIMIZEBOX」のみにすればいいというのは分かるんですが。
「fRet = SetWindowLong(hWnd, GWL_STYLE, fStyle)」この部分は全く分かりません。ただ、説明があるのでこの設定は絶対必要だというぐらいです。
「fRet = DrawMenuBar(hWnd)」ここも上記と同じです。

ほとんど分からないのですがすいませんが回答お願いします。

投稿日時 - 2007-12-09 21:50:52

お礼

今更ですが、お礼の記載が大変遅くなり、申し訳ありません。

ありがとうございました。

投稿日時 - 2015-05-23 17:27:19

あなたにオススメの質問