COMインターフェイスを通したAsprovaの機能の拡張

2011/10/04

COMインターフェイス

生産スケジューラAsprovaはCOMインターフェイスを公開し、EXEファイルやプラグイン(DLL)で機能を拡張することができます。EXEファイルやDLLファイルからメモリー上に展開されているプロジェクトオブジェクトを取得し、Asprovaの下位のテーブルオブジェクトにアクセスします。

Asprova本体は、イベントの発生タイミングにプラグインを実行させるためのHookを用意しており、このイベントを表すアクセスポイントであるプラグインキーが、Wordpressのdo_actionフックまたはapply_filtersフックに該当します。

自動車組み立て工程

インドネシアの生産スケジューラ

インドネシアの日系製造業においても生産管理システムが導入される事例が増えましたが、機械や設備の負荷を考慮した実現可能な生産計画作成という生産管理の主要課題については、Excelを使ったマニュアル作業で行われているのが現状で、今後生産スケジューラのニーズは高まるものと思われます。

続きを見る

COMインターフェイスとは

AsprovaはCOM (Component Object Model)で内部のデータや処理内容を公開する仕組みをもっており、プラグイン(ActiveX DLLファイル:Asprovaから関数呼び出し)やオートメーションクライアント(Standard EXEファイル:外部プログラムからAsprovaにアクセス)から機能追加することができます。

DLLファイルはAsprovaのEXEと同じフォルダに配置され、起動時にAsprovaに自動的に読み込まれます。

DLLはAsprovaの内部コマンドとして登録されますので、ユーザー定義メニューにくっつけてAsprovaからDLLを呼び出しますが、EXEの場合はプロジェクトファイルの名前を指定して開くことでアクティブなプロジェクトを取得します。

 

DLLの配置場所

DLLは起動するEXEから見て以下の場所に配置する必要があります。

  1. EXEとDLLを同じディレクトリに配置する。
  2. EXEを起動する際にDLLのディレクトリをカレントディレクトリとして起動する。
  3. DLLをsystem32ディレクトリに配置する。
  4. DLLをWindowsディレクトリに配置する。
  5. Path環境変数にDLLの配置しているディレクトリを設定する。

開発環境の参照設定(プラグイン内からAsprovaのライブラリを使用)

参照設定はGUIを持たないActiveXオブジェクトのタイプライブラリをプロジェクトで利用するためにプロジェクトファイル(.vbpファイル)内に保存され、プラグイン(プロジェクトファイルをコンパイルしたDLL)からCOMインターフェイスを通してAsprovaのライブラリにアクセスします。

参照設定によりDim変数宣言の際にそのオブジェクトの型を使用することが出来たり、new 演算子でインスタンスを生成することが出来るようになります。

  1. Asprovaプロジェクトクラス
    Dim project As aslib.ASBProject
  2. 拡張プラグインDLLで使うプラグインキーに関連のあるオブジェクトのリスト
    Dim ArgList As ASPArgList
  3. 品目クラス
    Dim item As ASBItem

プラグインからAsprovaのライブラリを参照する場合、下記の2つのAsprovaのクラスライブラリを開発環境の参照設定から登録します。

  1. As 1.1 Type Library
  2. AsPlugInManager 1.0 Type Library

プラグインのプロジェクトファイルの構成

プラグインの場合、Asprovaから呼び出す関数をASDefaultクラスのAutoRegistrationメソッドに登録します。

Asprovaの「プラグイン情報」にプラグインとして登録しておけばAsprova起動時にAutoRegistration関数が自動的に呼ばれ、プロジェクトオブジェクト内に実装されます。

COMポート2

Standard EXE(オートメーションクライアント)の場合はASDefaultクラスは必要ありません。

Asprovaのプラグインマネージャー(プラグイン登録関数)のAddASPlugInメソッドに4つの引数を渡すことによりプラグインを登録しますが、その内容は「自分はFactoryというプロジェクトで、OvertimeというクラスにAddOverTimeというメソッド(エントリ関数)を用意しているから、プラグインキーKeyHookGenericのタイミングで呼んでください」というものです。

プラグインキー(アクセスポイント)に対応するフックと関数のマッピング

Asprovaはあるイベントごとにプラグインを実行させるためのフックを設けています。

この各イベントを表すアクセスポイントをプラグインキーと呼び、例えばKeyHookGenericは「コマンドの追加」、つまり追加したコマンドが起動するタイミングのアクセスポイントで、コマンドを実行することによりプラグインを実行させます。

Option Explicit
Public Function AutoRegistration(plugInManager As ASPPlugInManager, module As ASPModule) As Boolean
    'このモジュールのコメントを設定します
    module.Comment = "APS Extended Functionality PlugIns (VB)"
    'プラグインオブジェクトを保持する変数を定義します
    Dim plugIn As ASPPlugIn
    ' ---------------------------------------------------------------------------------------------
    'プラグインマネージャを呼び出し、新しいプラグインを登録します。呼び出しメソッド名はAddASPlugIn です
    ' 第1Param:プラグイン表示名
    ' 第2Param:プラグインが実装されているモジュール及びクラスを表すProgID
    ' 第3Param:プラグインのエントリ関数名(呼び出し名)
    ' 第4Param:プラグインが使用されるコンテキストを表すキー名

    '(1)オーバータイムや土日残業を自動的に計算しカレンダーテーブルにセットする
    Set plugIn = plugInManager.AddASPlugIn("オーバータイムを残業と土曜出勤に組み込む", "Factory1.OverTime", "AddOverTime", ASPlugInKeyName.KeyHookGeneric)
    'このプラグインにコメント等などを設定します。

    plugIn.Comment = "オーバータイムを平日残業2時間と土曜2シフト出勤に割り振る。"
    'プラグイン呼び出し順(同一プラグインキーのプラグインが複数あったときのため)
    plugIn.Order = 1
    '自動登録が正常に行われたという事でTrue を返します。
    AutoRegistration = True
End Function

Asprovaは起動時にプラグインを自動的に読み込むと、内部コマンドのプラグインに「エントリ関数の表示名」(プラグインマネージャ呼び出し時の第一引数)を表示させます。

プラグインの中からAsprovaのプラグインマネージャーを呼び出し4つの引数を渡すことによりプラグインを登録します。
COMポート3

COMポート(communication port)のポートと同じ考え方

ついでに言うとCOMポートとCOMインターフェイスのCOMは別物ですが、外部インターフェイスとの標準規格という意味ではCOMポートもCOMインターフェイスも同じもです。

ソフトウェアやハードウェアには、外部とデータを入出力するためにデータの受け渡しの方法を標準化したインターフェース(ポート)を持っています。例えばPOPとSMTPサーバーのポート、DBに接続するときのポートはいずれもTCP/IPのポートです。

標準的なパソコンは、キーボードなどの周辺機器を接続するためのインターフェースとしてPS/2ポートやUSBポート、LANポート(Ethernetポート)などを備えています。

ソフトウェアの場合、外部の装置や通信ネットワークとのデータの送受信を標準的な方法で統一的に扱う方法がOSなどによって提供されており、通信相手などを識別するのにポートが使われます。

Windowsではモデムやプリンタ、イメージスキャナなどにアプリケーションソフトが統一的な方法でアクセスできるよう、入出力方式を統一した「COMポート」という仕組みが提供されており、アプリケーションソフトは自分の対象とする機器がどのCOMポートに接続されているかを知るだけで、当該機器との入出力が取り扱えるようになります。

例えばUSBバーコードを接続する場合にはCOM13が割り当てられますが、物理的にPCには13個もインターフェイスは存在しないのでCOM13というポートはあくまで仮想的なものです。

TCP/IPを利用したネットワーク通信では、通信機器や個々のコンピュータの持つIPアドレスの下に設けられた補助アドレスとして、0から65535までの「ポート番号」が使われます。

これにより、1台のコンピュータで複数のサービスを提供したり、複数のコンピュータと同時に通信できるようになっています。単に「ポート」といった場合には、このTCP/IPのポート番号を指すことも多いです。

レコードセットのフィールド値をttxファイルを介してCrystal reportのフィールド定義にマッピング

Asprovaの作業テーブルをAccessにエクスポートして現品票を発行します。

古いですがCrystal report 9にはParameter Fieldがあるので、VBからPassing Parameterするのかと思いきやRecord Setを放り投げると勝手にフィールドから値を取ってくれるので、Crystal Report Viewerという無償のActiveXコンポーネントビューアーの中にレポートを表示できます。

    CrRep.Database.SetDataSource rs, 3, 1
    CRViewer91.ReportSource = CrRep
    CRViewer91.ViewReport

それがこの部分。3番目の引数1がTable Numberを表します。

    '選択されたコンボのORDERCODを取得
    result = Combo1.List(Combo1.ListIndex)

    'Passing parameter from VB6 to CR using CRAXDRT
    Dim CrApp As CRAXDRT.Application
    Dim CrRep As CRAXDRT.Report

    'ORDERTBLからORDERCODのレコードセットを取得
    Dim conn As New ADODB.Connection
    Dim rs As ADODB.Recordset

    Dim mySQL As String

    cn.Open _
        "Provider = Microsoft.Jet.OLEDB.4.0; " & _
            "Data Source = " & CurDir & "\NNA.mdb"

    Set CrApp = New CRAXDRT.Application
    Set CrRep = CrApp.OpenReport(App.Path & "\reports\TravelSheet.rpt", & _
                    crOpenReportByTempCopy)

    CrRep.DiscardSavedData

    If result <> "ALL" Then
        mySQL = "SELECT * FROM OPERATIONTBL WHERE ORDERCOD='" & _
            Combo1.Text & "' ORDER BY ORDERCOD"
    Else
        mySQL = "SELECT * FROM OPERATIONTBL ORDER BY ORDERCOD"

    End If
    With rs
        .ActiveConnection = cn
        .CursorLocation = adUseServer
        .CursorType = adOpenKeyset
        .LockType = adLockOptimistic
        .Properties("IRowsetIdentity") = True

        .Open mySQL
    End With
    CrRep.Database.SetDataSource rs, 3, 1
    CRViewer91.ReportSource = CrRep
    CRViewer91.ViewReport

ところがCrystal Report ViewerのようなWin7での標準以外のコンポーネントを使った開発アプリはXPで問題起こす可能性大であり、crviewer9.dllが古いPCで問題起こしまくりなので、まずCR8.5にダウングレードした上で、以下にコード変更。

CR8.5はフォームレイアウトだけに限定させるために、ttxファイルにフィールド定義を行いVBからレコードセットを投げてttxファイルのField Definitionに従ってフォームにはめ込む。

Dim result As String

    '選択されたコンボボックスのORDERCODを取得
    result = Combo1.List(Combo1.ListIndex)

    'ORDERTBLからORDERCODのレコードセットを取得
    Dim conn As New ADODB.Connection
    Dim rs As ADODB.Recordset

    Dim mySQL As String

    cn.Open _
        "Provider = Microsoft.Jet.OLEDB.4.0; " & _
            "Data Source = " & CurDir & "\DNN.mdb"

    If result <> "ALL" Then
        mySQL = "SELECT * FROM OPERATIONTBL WHERE ORDERCOD='" & _
                    Combo1.Text & "' ORDER BY ORDERCOD"

    Else
        mySQL = "SELECT * FROM OPERATIONTBL ORDER BY ORDERCOD"

    End If

    rs.Open mySQL, cn, adOpenKeyset, adLockOptimistic

    With rptControl
        .WindowTitle = "Travel Sheet"
        .ReportFileName = App.Path & "\Reports\TravelSheet.rpt"

        .SetTablePrivateData 0, 3, rs
        .WindowShowPrintBtn = True
        .WindowShowPrintSetupBtn = True

        .RetrieveDataFiles
        .WindowState = crptMaximized
        .Destination = crptToWindow
        .Action = 1
    End With

CRファイルのReport Expertでttxファイル(rpt.ttx)を指定してあげると、コード内のレコードセットのフィールド値が自動的にCRファイルのフィールドにマッピングされます。

reportexpert

ttxファイルにタブ区切りでフィールド名、属性、長さを定義するやり方は日本では既に古典の部類に入る手法でしょうが、インドネシアではまだまだ現役です。

ORDERCOD	string	100
PROCNO	number
RESOURCE	string	100
ITEM	string	100
QTY	number
STARTDATE	string	100
ENDDATE	string	100
WORKTIME	string	100
PARENTITEM	string	100
CLASS	number

VBからJet Database Engineにアクセス

参照設定から「Microsoft ActiveX Data Objects 2.1 Library」 を追加。

Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset

conn.Open _
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _
"Data Source = C:\Users\Toshiba\Desktop\ERP\VB\LinkWithERP.mdb"

'DELETE
Dim query1 As String
query1 = "DELETE * FROM ORDER_SOURCE"
rs.Open query1, cn, adOpenKeyset, adLockOptimistic

'SELECT
Dim query2 As String
query2 = "SELECT * FROM ORDER_SOURCE"
rs.Open query2, cn, adOpenKeyset, adLockOptimistic

Do Until rs.EOF
    X1 = rs!Order_Code
    X2 = rs!Order_Item
    X3 = rs!Order_Qty

    rs.MoveNext
Loop

ADOやODBCはJet Database Engine(MDB)を利用するためのミドルウェアです。

MS-Access 形式の MDB ファイルの実体は Jet Database Engine(Microsoft社が開発したリレーショナルデータベースエンジン)ファイル、つまり単なるデータ格納用のコンテナであって、GUI を提供する Microsoft Access アプリケーションとは、独立した別個のファイルです。

つまりMDB ファイルは、MS-Access がインストールされていない環境下でも使用することは可能であるということを意味します。

MS-AccessがインストールされていないPCでExcel VBAでADOを使ってテーブル操作したり、MSのサイトからRuntimeをダウンロードして開くことも可能、しかもライセンスの制限に抵触しません。

Runtimeとは「アプリケーションの開発・実行の両方の機能を備えたソフトウェアから、開発の機能を省き、実効の機能のみを取り出したプログラム」のことです。つまり「実行環境 without 開発環境」です。

  • http://www.microsoft.com/ja-jp/download/details.aspx?id=4438

メモ帳はテキストファイルを編集するためのユーティリティだけれど、別にメモ帳だけがテキストファイルを編集できる唯一のアプリケーションというわけではない、というのと全く同じ理屈です。

システムからDB(RDB)への接続はADO接続かODBC接続かのどちらかがほとんどですが両者の違いは

  • ADOはOLEDBをActiveXコントロールとして操作するためのインターフェース
  • ODBCはOLEDBのうちRDBを提供するインターフェース

OLEDBの中にODBCプロバイダがあってRDBへ接続してくれるが、開発者はADOのインターフェースでOLEDBにアクセスできる。

Cikarangまで「開発者⇒ODBC⇒OLE(RDB・Excelなど)」という下道で行くと3時間はかかるが、「開発者⇒ADO⇒OLE(RDB・Excelなど)」というTol(高速道路)に乗ると1時間半で着くのと同じですw。

ちなみに接続オブジェクトとレコードセットオブジェクトの生成方法だがどれでもいいと思います。

CreateObject関数を使って新規オブジェクト変数を生成し、Setでオブジェクトへの参照をオブジェクト変数に代入します。

Dim conn As Variant
Dim rs As Variant
Set conn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")

Newを使ったオブジェクト参照の代入は、SetでNewを使って新しくオブジェクトを作成し、オブジェクト変数にオブジェクトの参照を代入します。

Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset

VBからMySQLにアクセス

PCがWindows 64bit版でも開発環境であるVB6は32bitなのでMySQL ODBC Connectorも32bit版を使用します。

ADODB接続の場合は関係ないですが、DSN接続をする場合に32bit版のODBCドライバを64bit版Winにインストールすると、コントロールパネルからODBC設定画面を起動してもインストールしたはずのMySQL5.1ドライバが表示されずあせります。よってコマンドプロンプトから以下のコマンドで32bit版のODBCデータソースアドミニストレーター画面を表示させDSN設定を行います。

  • %windir%\SysWOW64\odbcad32.exe

DSN接続の場合

'Mysql5.1ドライバ用DSN用接続オブジェクト生成
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset

Dim dsn As String
dsn = "dsn=xxx;uid=yyy;pwd=zzz"
conn.Open dsn
conn.CursorLocation = 3

ADODB接続の場合

'Mysql5.1ドライバ用ADO用接続オブジェクト生成
Dim conn As New ADODB.Connection
Dim rs As ADODB.Recordset

Dim strConn, xServer, xDatabase, xUID, xPass As String
If conn.State = 0 Then
    xServer = "localhost"
    xDatabase = "xxx"
    xUID = "yyy"
    xPass = "zzz"

    strConn = "DRIVER={MySQL ODBC 5.1 Driver};SERVER=" & xServer & _
               ";PORT=3306" & _
               ";DATABASE=" & xDatabase & _
               ";USER=" & xUID & _
               ";PASSWORD=" & xPass & _
               ";OPTION=3;"
    conn.Open strConn
End If

'DELETE
Dim query1 As String
query1 = "DELETE * FROM ORDER_SOURCE"
rs.Open query1, strConn

'SELECT
Dim query2 As String
query2 = "SELECT * FROM ORDER_SOURCE"
rs.Open query2, strConn

Do Until rs.EOF
    X1 = rs!Order_Code
    X2 = rs!Order_Item
    X3 = rs!Order_Qty

    rs.MoveNext
Loop

VBからExcelにアクセス

参照設定からMicrosoft Excel 12.0 Object Libraryを追加。

'Excel関連オブジェクト
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet

'ファイル名(フルパス)
Dim strFilename As String
strFilename = "C:\SO\Delivery Schedule.xls"

'シート名
Dim strSheetName As String
strSheetName = "Delivery Schedule"

'Application生成
Set xlApp = CreateObject("Excel.Application")

'EXCELを開く
'xlApp.Workbooks.Open FileName:=strFilename, UpdateLinks:=0

'Workbookオブジェクト生成
'Set xlBook = xlApp.Workbooks(Dir(strFilename))
Set xlBook = xlApp.Workbooks.Open(strFilename)

'Worksheetオブジェクト生成
Set xlSheet = xlBook.Worksheets(strSheetName)

'Worksheetデータの取得
Dim cnt As Integer
cnt = 1

Do
    'ORDCOD = Worksheets("Delivery Schedule").Cells(cnt, 1).Textでも取得可
    ORDCOD = xlSheet.Cells(cnt, 1).Text
    ORDITM = xlSheet.Cells(cnt, 2).Text
    ORDQTY = xlSheet.Cells(cnt, 3).Text

    cnt = cnt + 1
Loop While ORDCOD <> ""

ちなみにブックオブジェクト生成の際のファイル名(フルパス)を変数から代入する場合、拡張子を削除してあげないと何故か取得できません。ただし上例のように固定パスを文字列で代入する場合は問題ないです。

InStrRevでピリオドの位置を取得し拡張子を除外します。

strFilename = CurDir & "\data\" & strFilename
'拡張子を削除する(これをやらないとエラーになる)
strFilename = Left(strFilename, InStrRev(strFilename, ".") - 1)

Set xlBook = xlApp.Workbooks.Open(strFilename)

ワークシート名の取得と追加は以下のとおり。

'ワークシート名の取得
j = 0
For Each ws In xlBook.Worksheets
    sheetArry(j) = ws.Name
    j = j + 1
Next

'ワークシート6の追加
Set xlSheet = xlBook.Worksheets.Add  'ワークシートを追加
xlSheet.Name = "New sheet"

VBからテキストファイル(CSV)にアクセス

参照設定からMicrosoft Scripting Runtimeを追加。FileSystemObjectはWindowsでファイルシステムを簡単に扱えるようにするためのコンポーネントです。

'DB接続オブジェクトとレコードセットオブジェクト生成
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset

'CSVファイルを扱うためのコンポーネントオブジェクト生成
Dim objFSO As New Scripting.FileSystemObject

'DBに接続
conn.Open _
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _
    "Data Source = " & CurDir & "\SO.mdb"

'SELECTでレコードセット生成(空)
query1 = "SELECT * FROM ORDER_SOURCE"
rs.Open query1, conn, adOpenStatic, adLockOptimistic

'CSVファイルのデータをオブジェクトに読み込む
Set objFile = objFSO.OpenTextFile("C:\APS_ERP\VB\" & CSVNAME)

'1行ずつ読み込みレコードセットに格納
cnt = 0
Do Until objFile.AtEndOfStream
    strMastflow = objFile.ReadLine
    arrMastflow = Split(strMastflow, ",")

    rs.AddNew
    rs("Order_Code") = arrMastflow(0)
    rs("Order_Item") = arrMastflow(1)
    rs("Order_Qty") = arrMastflow(2)
    rs.Update

    cnt = cnt + 1
Loop

OLE DB関連用語

ADOを通してDBアクセスするまでのミドルウェアやコンポーネントの関係は、荷送り人(Shipper)から荷受人(Consignee)に荷物を海上輸送する過程に似ていると思います。

oledb

開発アプリケーションプログラム(Shipper)からRDBやExcel, Texfile(Consignee)にアクセスするには、OLE DBデータプロバイダーという仲介人(Forwarder)に手続きをお願いしますが、直接OLE DBとやりとりするのはややこしい書類手続きなど煩わしいので、ADO(カーゴ業者)にやってもらいます。

  • OLE DB(Object Linking and Embedding DataBase)
    Microsoft社によって開発された、データベースの種類によらず統一的な手法でデータベースにアクセスするためのプログラミングインターフェース。
    つまりDB(Consignee)<< OLE DBはCOMコンポーネント(プログラム部品)の集合体として実現され、どんなプログラミング言語からでも利用することができるようになっている。OLE DB は概念的に「コンシューマ (consumer)」と「プロバイダ(provider)」に分けられる。コンシューマとはデータにアクセスする必要のあるアプリケーションであり、プロバイダはインタフェースを実装したソフトウェアコンポーネントで、コンシューマにデータを提供する。
  • COMインターフェイス
    COM (Component Object Model)で内部のデータや処理内容を公開する仕組みで、プラグイン(ActiveX DLLファイル)やオートメーションクライアント(Standard EXEファイル)からアプリケーションが公開している機能にアクセスしプラグインを開発・公開できるようになっている。
  • ADO(ActiveX Data Object)とはOLE DBプロバイダを介してデータベースにアクセスするためのコンポーネント。OLE DBをActiveXコントロールの形で使えるようにしたプログラミングインターフェース。ADOを利用してVBからテーブルレコードを直接操作できる。
  • ActiveXコントロールは従来OLEコントロールと呼ばれていた技術にインターネットに対応するための拡張を施したもの。ActiveXコントロールはネットワークを通じてWebサーバからダウンロードされ、同社のWebブラウザであるInternet Explorerに機能を追加する形で使用される。

プラグインDLLは機能(関数)の追加、拡張インターフェイスDLLは既存ロジックに対する変更のために開発します。

AsDefaultクラスのAutoRegistrationメソッドの中にプラグインキー(KeyHookGeneric)を定義するか、インターフェイス(IEIIFilterCalc ReplenishOrderLotSizing)を定義するかの違いです。

プラグインキーとインターフェイスの違い

プラグインのAsDefaultクラスのAutoRegistrationメソッドの中のエントリ関数呼び出し部分にプラグインキー(KeyHookGeneric)を定義しておけば、Asprovaで該当するイベントが発生(追加したコマンドが起動)したときにエントリ関数が呼び出され実行される。

同じようにEII(Extension Interface Implementation)のAsDefaultクラスのAutoRegistrationメソッドの中のエントリ関数呼び出し部分にインターフェイス(IEIIFilterCalc ReplenishOrderLotSizing)を定義しておけば、Asprovaで該当するイベントが発生(自動補充発生)したときにエントリ関数が呼び出され実行される。

ただしプラグインキーよりもインターフェイスは呼び出しにかかるオーバーヘッドが小さくなるようカスタマイズされており、オーダ展開、自動補充、ロットまとめなどのような頻繁に呼び出しがかかるロジックの変更に適しています。

プラグインDLLは機能(関数)の追加、拡張インターフェイスDLLは既存ロジックに対する変更のために開発します。

プラグインDLL
拡張インターフェイスを使うとプラグインキーを使うよりも呼び出しにかかるオーバヘッドが小さいので、リスケジュールの中で頻繁に発生するイベントから呼び出したいエントリ関数を追加する場合に使用します。

補充オーダのロットサイズを変更する拡張インターフェイス(DLL)

補充オーダのロットサイズは「製造ロットサイズMAX」「製造ロットサイズMIN」「製造ロットサイズUNIT」によって決まりますが、FilterCalcReplenishOrderLotSizingは「オーダ展開」コマンドの中での紐付け時に呼び出され、以下の3つのオブジェクトを取得して補充オーダのロットサイズを変更(上書き)し、結果をArgListに渡します。

  1. 補充品目の配列 ArgAsObject(kArgItem)
  2. 親オーダの初工程の作業入力指図のリスト ArgAsObject(kArgObjectList)
  3. ロットサイズのリスト ArgAsSafeArray(kSafeArrayArgDouble)

ロットサイズ

  1. ロットサイズは自動補充「はい」
  2. ロットサイズは補充オーダ生成時に決定される
  3. 作業入力指図のリスト(2次元配列)と作業出力指図のリスト(品目)

オーダ展開のプロセス

  1. 親オーダの作業(作業入力指図と作業出力指図)を生成
    初期状態での親オーダとは受注オーダ、または登録オーダの製造オーダ
    製造BOMより作業入力指図、作業出力指図を生成
  2. 自動補充
    親オーダの作業の作業入力指図が紐付け対象かどうか確認
    親オーダが在庫(絶対量)よりも過去の日時の場合、
    作業入力指図は紐付け対象外不足分の作業入力指図の製造オーダを自動生成する。
    親オーダの作業入力指図(入力品目)の不足分の製造オーダを子オーダとして生成
    子オーダの作業入力指図の不足分の製造オーダを孫オーダとして生成
  3. オーダ間の紐付け1回目
    自動補充設定のある受注オーダ、製造オーダ、購買オーダ、在庫オーダの紐付け
    自動補充設定のない製造オーダ同士(製造BOMで繋がりのある品目同士)

製造オーダ完成7回分で前工程をまとめる例

  1. 1回目の自動補充でitemにB1が、instにBのリストが入る
    作業M4の入力指図B1の不足数量(在庫がないのでRemainingQtyはBそのもの)を7回足しこむ
  2. 2回目の自動補充でitemにCが、instにAのリストが入る
    作業M2の入力指図Cの不足数量を7回足しこむ。
  3. inst.Operation.OperationMainRes.Code='M4'が条件なので(2)は実行されない。

プラグインDLL

Asprovaの各テーブルにアクセスするためには、メモリ上に展開されているAsprovaのプロジェクトオブジェクトを通す必要があり、このプロジェクトオブジェクトの取得方法はDLLとEXEでは異なります。DLLの場合は引数argsにASPArgListというプラグインキーに関連のあるオブジェクトのリストをロードしここからプロジェクトオブジェクトを取得しますが、EXEの場合は所定のプロジェクトファイルをロードしたドキュメントオブジェクトからアクティブなプロジェクトを取得します。

拡張プラグイン(DLL)の場合

'(ASPArgList内にあるオブジェクトの定義と取得)
'------------------------------------------------------------------
Public Function AddPersonPlan(args As ASPArgList) As TReturnType

    'APSの各テーブルのオブジェクトにはプロジェクトオブジェクトからアクセスする
    'プロジェクトオブジェクトはargsインターフェイスから取得
    'ASPAgrListオブジェクトからプロジェクトオブジェクトをASBProject型変数に代入することにより引数を受け取る

    Dim project As aslib.ASBProject
    Set project = args.ArgAsObject(kArgProject)

    'プロジェクトオブジェクトからRootObjectをASORootObject型変数に代入
    Dim root As aslib.ASORootObject
    Set root = project.RootObject

    'プロジェクトオブジェクトからRootCalendarオブジェクトをASBCalendar型変数に代入
    Dim calendarRoot As aslib.ASBCalendar
    Set calendarRoot = project.RootCalendar

    'プロジェクトオブジェクトからRootResourceオブジェクトをASBResource型変数に代入
    Dim resourceRoot As aslib.ASBResource
    Set resourceRoot = project.RootResource

    'プロジェクトオブジェクトからorderRootオブジェクトをASBOrder型変数に代入
    Dim orderRoot As aslib.ASBOrder
    Set orderRoot = project.orderRoot

    'プロジェクトオブジェクトからitemRootオブジェクトをASBItem型変数に代入
    Dim itemRoot As aslib.ASBItem
    Set itemRoot = project.itemRoot

    'プロパティIDの格納用変数の定義
    Dim propID1 As Long

'(取得したオブジェクトへのアクセス)
'------------------------------------------------------------------
    'カレンダーオブジェクトの子供の数(レコード数)
    calendarCount1 = calendarRoot.ChildCount

    'ルートオブジェクトを使って資源コードのプロパティIDを取得
    propID1 = root.LookupPropID("Cal_Resource")

    'レコードが終了するまでループ
    'ChildAsCalendarの引数は1から(0は最後のデータを表す)
    For i = 1 To calendarCount1
        'レコードにアクセス
        Set calendar = calendarRoot.ChildAsCalendar(i)

        'GetAsStrメソッドでプロパティの値にアクセス。プロパティが配列値でなければ2番目の引数は1を設定
        res1 = calendar.GetAsStr(propID1, 1)
    Next

End Function

Standard EXEの場合

プラグインや拡張インターフェイスとは異なり、Asprovaの外にあるEXEプログラムからAsprovaのオブジェクトを取得する必要があります。この場合はドキュメントオブジェクトに所定のプロジェクトファイルをロードし、ドキュメントオブジェクトからアクティブなプロジェクトを取得します。

Private Sub Command1_Click()

    '■■■Asprova関連オブジェクト■■■
    'Asprovaプロジェクトオブジェクト定義
    Dim m_pProject As ASBProject
    Dim m_pDoc As ASFDocument

    'アスプローバアプリケーションを取得
    Dim app As ASFApplication
    Set app = New ASFApplication

    'アスプローバドキュメントの名前を指定して開く
    Set m_pDoc = app.Deserialize(CurDir & "\data.aru")

    'アクティブなプロジェクトをドキュメントから取得
    Set m_pProject = m_pDoc.ActiveProject

    '■■■作業テーブルから末端オーダ品目でマッチング■■■
    '作業オブジェクト取得
    Dim operation As ASBOperation
    Dim operationList As ASOObjectList
    Set operationList = m_pProject.GetOperationList(False)

    'ルートオブジェクトの取得
    Dim root As ASORootObject
    Set root = m_pProject.RootObject

    'propIDの取得(rootオブジェクトから取得)
    propID1 = root.LookupPropID("Work_OperationOutMainItemQty")

    'プロジェクト全体の作業を取得して1発マッチング
    operationList.FilterByExprStr ("WorkUser_MostRightOrderItem=='" & Left(Combo1.Text, 7) & "')

    '製造開始日時の昇順でソートする。
    operationList.SortByExprStr ("Work_OperationProductionStartTime,a")

    Do
        'リストのデータを取得
        Set operation = operationList.Object(i)
        '値の取得
        PrdQty = operation.GetAsStr(propID1, 1)
        '値の保存
        operation.SetAsStr propID1, 1, Text1.Text

        i = i + 1

    Loop While i <= operationList.ObjectCount

    '■■■資源テーブルのデータを1件ずつチェック■■■
    '資源オブジェクト定義
    Dim RootResource As AsLib.ASBResource
    Dim resource As AsLib.ASBResource

    '資源ルートオブジェクトの取得
    Set RootResource = m_pProject.RootResource

    'propIDの取得(rootオブジェクトから取得)
    propID2 = root.LookupPropID("Res_Code")

    '資源テーブルのレコード数
    ResourceCount = RootResource.ChildCount

    For i = 1 To ResourceCount
        Set resource = RootResource.ChildAsResource(i)
        ResCode = resource.GetAsStr(propID2, 1)

    Next i

    '■■■品目テーブルから品目コードでマッチング■■■
    '品目オブジェクトの定義
    Dim RootItem As ASBItem
    Dim Item As ASBItem

    '品目ルートオブジェクトの取得
    Set RootItem = m_pProject.RootItem

    '品目オブジェクトの取得
    Set Item = RootItem.FindChild(Left(Combo1.Text, 7))

    '品目テーブルでマッチしたレコード数
    ItemCount=Item.ChildCount
End Sub