愚者の経験

「また今度」はほとんどこない

月別アーカイブ: 1月 2013

API宣言の書き方は「今後」どうすればいいか

旧バージョンとの互換性、アーキテクチャ(86/64bit)の互換性を意識して
APIを記述するには何が一番良いか考えてみます。

先に結論を書きますと
64bit版が登場したOffice2010以上とそれ未満では互換性のとりようがない」です。

64bit版が登場したOffice2010からVBAのバージョンが[7]にアップし
API宣言が変化しました。(元の宣言が出来ないわけではありませんが64bit版ではコンパイルエラー)

        Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)

ここで言うと「PtrSafe」と「LongPtr」です。64bit版専用に「LongLong」という型も存在するようですが
「LongPtr」が自動判別(32bitならLong型、64bit型ならLongLong型)してくれるため別にいいのです。

Office2010以上であれば上記の書き方で32bitでも64bitでも動作します。
ですが2007以下も入ってくるとVBAのバージョンは6になるので
残念ながら2通り記述する必要があります。

#If VBA7 Then 
    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr)
#Else
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If

上記のようにすればにしてもコンパイルは確かに通りますし、両方で動作します。
しかしVBA6側では文字が赤くなってしまいます。なのでVBA6側からAPIを直そうとする場合
コンパイルエラー「修正候補:Sub または Function」と戦い続けるはめになります(笑)

XPにOffice2013はインストール不可

「サポートしない」って言っても2種類あると思います。
1.そもそもインストールできない、させない
2.動作保証しない

Office2013は前者になります。Vistaも多分無理でしょう。
xp2013

Office 2010と2013を共存させるとやっぱり切り替え必要

Office2013Preview版はバージョン切り替えが発生しなかったみたいですが
それはPreview版が「Microsoft Application Virtualization (App-V)」
形式(っていうのか)で配布しているからで製品版をインストールすると
切り替えはやっぱり発生しそうです。

office2013

それにしてもこのAccess2013、拡張子「adp」サポートしてないのにしっかりと
アイコン変えてます。もちろん起動できません。ほっといてほしいと思うのは私だけ?
そうすれば切り替えこそすれ2010で起動するのに。

「Ctrl+7」の怪

テキストボックスのBeforeUpdateに

Private Sub txt1_BeforeUpdate(Cancel As Integer)
    If (Nz(Me.txt1.Text, "") = "") Then
        Exit Sub
    End If
    
    ' 適当な処理
    MsgBox "test"
End Sub

と書いてました。よくある「入力があったら処理しない」です。
ところが「Ctrl+7」キーで入力すると処理しないのです。

これで入力したときは「Text」プロパティが長さ0になり「Value」プロパティに
値が入っている不思議な状態になります。

ポップアップしたフォームにApplication.Echoは無効

ヘルプにも書いてありますが、フォーム[ポップアップ]プロパティが「はい」の時
そのフォームに対して「Application.Echo False」しても無効です。
もちろん「Docmd.Echo False」でも同じです。

その場合どうするかといいますとやっぱりAPIを使います。

    Private Declare Function LockWindowUpdate Lib "user32" (ByVal Hwnd As Long) As Long

でもこれは他のアプリケーションとか重ねるとその画面でまた固まってしまいます。
なにかいい方法はないものか…

Office2013評価版とかいろいろ試す

「OfficeProfessionalPlus2013」を試してみました。
ファイル名は「OfficeProfessionalPlus_x86_ja-jp.img」です。

ADODB.Recordsetの不具合が直っていました!!個人的にかなりうれしいです。
Previewではフォームの「Recordset」プロパティにSetしてもデータが正しく
表示されてなかったのですが、上のOfficeでは正しく表示できているようです。
また、編集等もできたように思います。

これでストアドプロシージャで取得したデータを編集する方法が絶たれずに
済みました。

Access Proect(*.adp)でローカル一時テーブルを使う

またまたadpネタです。
adpでは「ローカルテーブルを持つことができない
という大きなハンデを抱えています。利用できるテーブルはすべてSQL Serverに作成
する必要があり、作業用のテーブルが必要な場合はSQL Serverの一時テーブル
(先頭に「#」を使ってCreate Table する構文)で作成できますが、これはセッション単位で
破棄してしまいます。

例えば以下のように

CREATE PROCEDURE [dbo].[sp_test] 
AS
BEGIN
	create table #temptbl (col1 INT PRIMARY KEY)
	
	select *
	from #temptbl
END

というストアドを作成してフォームのレコードソースに「sp_test」としたとしても、
データを入力することはできません。「tempdbのオブジェクトが」みたいなエラーが出ます。

ではユーザー(プログラム)別にテーブルを持つことは出来ないのかというと
VBAを使って可能です。

標準モジュールに以下のように記述します。

Option Compare Database
Option Explicit

Private cn As ADODB.Connection

Public Sub test()
    If (cn Is Nothing) Then
        Set cn = CurrentProject.AccessConnection        
        cn.Execute "CREATE TABLE #temptbl (col1 INT PRIMARY KEY)"
    End If
End Sub

フォームのストアドも修正します。CREATE TABLEを取るだけです。

ALTER PROCEDURE [dbo].[sp_test] 
AS
BEGIN
	select *
	from #temptbl
END

これでアプリケーションの開始時にtestプロシージャをコールしておけば
フォーム上で入力出来るローカルテーブルの出来上がりです。

testプロシージャではadpのコネクションを取得し、そのコネクション上でExecuteして
一時テーブルを作成します。この操作でAccessが持つセッションに
従属する(?)ローカル一時テーブルとなりフォームにバインド出来るようになります。

後はストアドで一時テーブルをselectしておけば編集可能になります。
起動と同時に作成し、アプリケーションの終了と同時に破棄されますので便利です。

create table ですがCurrentProject.AccessConnection.Execute ~~~
みたいに一行で実行してもいいです。

CREATE TABLEの文字列をスカラー関数にしてSQL Serverに
登録しておくことで一元管理もできそうです。

CREATE FUNCTION sf_test 
()
RETURNS nvarchar(max)
AS
BEGIN
	RETURN 'create table #temptbl (col1 INT PRIMARY KEY)'
END
GO
Option Compare Database
Option Explicit

Public Sub test1()
    Dim tblstr As String
    
    With CurrentProject.AccessConnection
        tblstr = .Execute("select dbo.sf_test()").Fields(0).Value
        
        .Execute tblstr
    End With
        
End Sub

ローカルテーブルが欲しい場合はおすすめ?です。
ところでAccess 2013 RTMになってADODB.Recordsetをフォームに
Set出来るようになったんでしょうか?実に気になります。