- PR -

ダイアログの表示位置

1
投稿者投稿内容
chiroru
ベテラン
会議室デビュー日: 2008/10/02
投稿数: 59
投稿日時: 2009-02-25 10:53
名前を付けて保存ダイアログの表示位置をしていしたいのですが、
このコーディングだと下記のエラーとなります。
'StartPosition' は 'System.Drawing.Printing.PrintDocument' のメンバではありません。
どう直せばいいのでしょうか?ご教授お願いします。
コード:
Public Function ShowDialog() As String
	Dim dialog As SaveFileDialog = New SaveFileDialog()
	Dim res As DialogResult
	dialog.StartPosition = FormStartPosition.CenterParent     ←はじめの表示位置を指定する
	dialog.Filter = "PDFファイル(*.pdf)|*.pdf"
	dialog.FileName = ""
	dialog.Title = "保存先のファイルを選択してください"
	res = dialog.ShowDialog()
	If res = Windows.Forms.DialogResult.OK Then
		〜省略〜
	End If
	dialog.Dispose()
	Return ""
End Function

レイル
常連さん
会議室デビュー日: 2008/10/14
投稿数: 37
投稿日時: 2009-02-25 15:36
VB.NETでしか確認できてませんが、
SaveFileDialogにStartPositionメソッドは実装されていないと思います。

StartPositionはformで使用可能なメソッドですね。

すみませんが、保存ダイアログの表示位置は私は分かりません。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2009-02-25 18:30
SaveFileDialog(及びOpenFileDialog)は、手の入れようが無い作りなので
容易に実現することは無理かと思います。


かなり面倒なやり方になってしまいますが
表示位置の指定を実現する方法が無いわけではありません。
(.NETの知識以外にもWindowsAPI&C++の知識も必要となります)

【方法】
直接Win32APIのGetSaveFileName()関数を呼び出す。
呼び出す際に渡すOPENFILENAME構造体のlpfnHookに
フックプロシージャを設定し、ダイアログ初期化(CDN_INITDONE)を捕らえ
表示位置を指定することで、一応実現可能となります。


コモンダイアログのカスタマイズについては
以前(.NET誕生前)から問題とされている内容です。
そのおかげで、かなりの情報がWebに蓄積されていますので
探せば(C++側の)サンプルコードは見つかるかと思います。
chiroru
ベテラン
会議室デビュー日: 2008/10/02
投稿数: 59
投稿日時: 2009-02-26 13:03
引用:

探せば(C++側の)サンプルコードは見つかるかと思います。


ありがとうございました。
ちょっと私には難しそうですね。
とりあえず、サンプルを探してみてみます。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2009-02-26 13:32
.NET(C#,VB.NET)からのずばりという利用サンプルは
見つけられなかったので作ってみました。

普段VB.NETは使用していないので変なコーディングをしているかもしれませんが、ご了承下さい。

コード:

Imports System.Runtime.InteropServices

Module Module1

Sub Main()

'' OPENFILENAME構造体を用意
Dim ofn As New Win32.OPENFILENAME()
ofn.lStructSize = Marshal.SizeOf(ofn)
ofn.lpstrFilter = "Text files" & ChrW(0) & "*.txt" & ChrW(0)
ofn.lpstrFile = New String(New Char(256) {})
ofn.nMaxFile = ofn.lpstrFile.Length
ofn.lpstrFileTitle = New String(New Char(64) {})
ofn.nMaxFileTitle = ofn.lpstrFileTitle.Length
ofn.lpstrInitialDir = "C:"
ofn.lpstrTitle = "名前を付けて保存 - 保存先ファイルを指定して下さい。"
ofn.lpstrdefext = "txt"
ofn.flags = &H80826
ofn.lpfnHook = AddressOf Win32.WinHookProc

Dim point As New Win32.POINT
point.x = 500 '' ダイアログの左上X座標
point.y = 100 '' ダイアログの左上Y座標

Dim lpPoint As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(point))
Try
Marshal.StructureToPtr(point, lpPoint, True)
ofn.lCustData = lpPoint

If Win32.GetSaveFileName(ofn) Then
Console.WriteLine("Selected File with Full-Path:[{0}]", ofn.lpstrFile)
Else
Console.WriteLine("Selected Cancel.")
End If
Finally
Marshal.FreeHGlobal(lpPoint)
End Try

#If DEBUG Then
Console.WriteLine("Push Key to End Debug...")
Console.ReadKey()
#End If

End Sub

End Module

'' フックプロシージャのデリゲート宣言(関数ポインタ)
Public Delegate Function HookProc _
(ByVal p_hWnd As Integer, ByVal p_uiMsg As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

Public Class Win32

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class OPENFILENAME
Public lStructSize As Integer = 0
Public hwndOwner As IntPtr = IntPtr.Zero
Public hInstance As IntPtr = IntPtr.Zero
Public lpstrFilter As String = Nothing
Public lpstrCustomFilter As String = Nothing
Public nMaxCustomFilter As Integer = 0
Public nFilterIndex As Integer = 0
Public lpstrFile As String = Nothing
Public nMaxFile As Integer = 0
Public lpstrFileTitle As String = Nothing
Public nMaxFileTitle As Integer = 0
Public lpstrInitialDir As String = Nothing
Public lpstrTitle As String = Nothing
Public flags As Integer = 0
Public nFileOffset As Short = 0
Public nFileExtension As Short = 0
Public lpstrdefext As String = Nothing
Public lCustData As IntPtr = IntPtr.Zero
Public lpfnHook As HookProc = Nothing
Public lpTemplateName As String = Nothing

'' 注:以下のメンバは最新のOPENFILENAME構造体のメンバとなります。
Public pvReserved As IntPtr = IntPtr.Zero
Public dwReserved As Integer = 0
Public FlagsEx As Integer = 0
End Class

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class NMHDR
Public hWnd As IntPtr = IntPtr.Zero
Public idFrom As Integer = 0
Public code As Integer = 0
End Class

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class OFNOTIFY
Public hdr As NMHDR
Public lpOFN As IntPtr = IntPtr.Zero
Public pszFile As IntPtr = IntPtr.Zero
End Class

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class POINT
Public x As Long
Public y As Long
End Class

Declare Auto Function GetSaveFileName Lib "Comdlg32.dll" _
(<[In](), Out()> ByVal ofn As OPENFILENAME) As Boolean

Declare Function SetWindowPos Lib "user32" _
(ByVal hWnd As Integer, ByVal hWndAfter As Integer, _
ByVal X As Integer, ByVal Y As Integer, _
ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Integer

Declare Function GetParent Lib "user32" (ByVal hWnd As Integer) As Integer

Public Shared Function WinHookProc(ByVal hWnd As Integer, ByVal message As Integer, _
ByVal wParam As Integer, ByVal lParam As Integer) As Integer

If message = &H4E Then '' &H4E = WM_NOTIFY
Dim lpNmhdr As NMHDR
'' WM_NOTIFYの際、lParamは、NMHDR構造体へのポインタ or NMHDR構造体を先頭に持つ構造体へのポインタ
lpNmhdr = Marshal.PtrToStructure(New IntPtr(lParam), GetType(NMHDR))

'' NMHDR.codeを見て、通知内容を確認。(CDN_INITDONEかを確認)
If lpNmhdr.code = (-601) Then
'' CDN_INITDONE時、lParamの正体はOFNOTIFY構造体
Dim lpOfn As OFNOTIFY
lpOfn = Marshal.PtrToStructure(New IntPtr(lParam), GetType(OFNOTIFY))

'' OFNOTIFY構造体には、OPENFILENAME構造体へのポインタが含まれる。
'' ポインタが示すOPENFILENAME構造体は呼び出し時に渡したOPENFILENAME構造体
Dim lpOpenFn As OPENFILENAME
lpOpenFn = Marshal.PtrToStructure(lpOfn.lpOFN, GetType(OPENFILENAME))

'' OPENFILENAME構造体に設定したカスタムデータ(今回はPOINT構造体)
Dim lpPoint As POINT
lpPoint = Marshal.PtrToStructure(lpOpenFn.lCustData, GetType(POINT))

If lpPoint IsNot Nothing Then
'' 当プロシージャに渡っているhWndはダイアログのハンドルではなく、子コントロールのハンドルなので
'' 子コントロールの親(つまりダイアログ)のハンドルをWin32API:GetParentで取得し
'' Win32API:SetWindowsPosで位置設定を行う
Win32.SetWindowPos(Win32.GetParent(hWnd), Nothing, lpPoint.x, lpPoint.y, 0, 0, &H1)
End If
End If
End If
Return 0
End Function

End Class


上記はあくまでもサンプルですので必要な処理(nullチェック等)は記述しておりません。

構造体メンバの意味や設定している値等については
調べるなり、再度質問するなりしてください。

[訂正]記述ミス訂正

[ メッセージ編集済み 編集者: くまっち 編集日時 2009-02-26 13:42 ]
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2009-02-26 13:51
引用:

chiroruさんの書き込み (2009-02-25 10:53) より:

dialog.StartPosition = FormStartPosition.CenterParent ←はじめの表示位置を指


うーん。 CenterParent (親コンテナの中央) だと .NET だけでは難しいですね。 Desktop WorkingArea の中央であれば別プロセスとして実行すれば行けそうな気はしますが。

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
1

スキルアップ/キャリアアップ(JOB@IT)