tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^3: COMP-3の変換につて
投稿日: 2017/09/22(Fri) 19:00
投稿者魔界の仮面弁士
> 元々は汎用機やサーバのCobolerでして、
私は逆に、COBOL の読み書きができないんですよね…。orz

.NET Framework 対応の COBOL 言語を数時間触ったことがあって、
COMP-3 形式 とかもその時に概念として齧ったことがある程度で。


> パック形式のシーケンシャルファイルから
> SQL-Serverに一括登録するプログラムを作っています。
SQL Server への格納が目的なのであれば、SQL Server 側で
 dbo.fn_varbintohexstr(@pack)
で 16進数化して、符号だけ切り出して decimal 変換するのも手かと思います。


たとえば後述の Transact-SQL を実行すると、下記の変換結果が得られます。

実際に使うときは、VARBINARY(もしくは 16進数文字列な VARCHAR)を受け取って
戻り値として DECIMAL を返すような FUNCTION を SQL Server 側に作成しておくと便利かと。


ID  HEX          VALUE
--- ------------ -------
例1 0x000489944c  489944
例2 0x000009834c    9834
例3 0x000015048c   15048
例4 0x000007982c    7982
例5 0x000011439c   11439
例6 0x01234d       -1234


-----------------------------
DECLARE @pack1 VARBINARY(255);
DECLARE @pack2 VARBINARY(255);
DECLARE @pack3 VARBINARY(255);
DECLARE @pack4 VARBINARY(255);
DECLARE @pack5 VARBINARY(255);
DECLARE @pack6 VARBINARY(255);

SET @pack1 = 0x000489944c;
SET @pack2 = 0x000009834c;
SET @pack3 = 0x000015048c;
SET @pack4 = 0x000007982c;
SET @pack5 = 0x000011439c;
SET @pack6 = 0x01234d;

WITH CTE1 (ID, VALUE) AS (
  SELECT '例1', @pack1 UNION ALL
  SELECT '例2', @pack2 UNION ALL
  SELECT '例3', @pack3 UNION ALL
  SELECT '例4', @pack4 UNION ALL
  SELECT '例5', @pack5 UNION ALL
  SELECT '例6', @pack6
), CTE2 (ID, HEX) AS (
  SELECT ID, dbo.fn_varbintohexstr(VALUE) FROM CTE1
), CTE3 (ID, HEX, VALUE) AS (
  SELECT ID, HEX, CASE
    WHEN HEX LIKE '0x%[a-f]_%' THEN NULL
    WHEN HEX LIKE '0x%c' THEN +1
    WHEN HEX LIKE '0x%d' THEN -1
    END * CONVERT(DECIMAL,
    REPLACE(REPLACE(REPLACE(HEX, 'd', ''), 'c', ''), '0x', ''))
  FROM CTE2
) SELECT * FROM CTE3 ORDER BY ID



> 厚かましいとは思いますが、実験で作られたプログラムの解説をお願い
> できないでしょうか。本当に申し訳ありません。

実験コード自体の解説をしても、あまり意味は無いと思いますよ。

今回の問題は、COMP3_CNV_RTN に渡すべき「データ」を
どこからどうやって取得しているのかが問題だからです。

渡すべきデータが間違っている(というか破損している)ために生じた問題ですので、
最初に御提示頂いたコードだけを見ても、原因は特定できません。

『パック形式のシーケンシャルファイル』を読み取っているコードを見せてください。
ついでに、変換元ファイルの具体的な内容も分かると説明しやすいです。



>> ループカウンタすらローカル変数になっていないなど、
>> モジュールレベル変数(フィールド変数)を使いすぎな点が気にかかります。
> 元々は汎用機やサーバのCobolerでして、ご指摘のようなことを気にして
> おりませんでした。以後は気を付けます。

ほとんどの変数は、ローカル変数として宣言されるべきです。
(ローカル変数とは、Sub〜End Sub / Function〜End Function の中で宣言される Dim のことです)

また、処理結果を返却するためには、Function の戻り値を使うのが望ましいです。
たとえば今回のケースなら、COMP3_CNV_RTN の実装は、
 Function COMP3_CNV_RTN(ByRef C3() As Byte) As String
もしくは
 Function COMP3_CNV_RTN(ByVal C3 As String) As String
などとするのが良いと思います。CNT 引数をつけるかどうかはお好みで。



> ByValに関しては理解できていないためです。
今回の『Sub COMP3_CNV_RTN(C3 As String, CNT As Integer)』の場合、
Sub COMP3_CNV_RTN(ByVal C3 As String, ByVal CNT As Integer)
にした方が良いということです。

引数に ByVal も ByRef もつけなかった場合、VB6 では ByRef 扱い、VB.NET では ByVal 扱いになります。


ByVal は「呼び出し元からデータを受け取る」ためのものですが、
ByRef は「呼び出し元にデータを返却する」ための出力引数です。
(ただし VB6 では、配列やユーザー定義型を渡す場合は、ByVal 扱いにできません)


今回の COMP3_CNV_RTN の中では「C3 の内容を読み取る」ことはあっても、
「呼び出し元に返却するために C3 の内容を書き換える」ことはないので、
ByVal をつけるべきである、ということです。


また先の例においては、Command1 のコードにて
 Dim bin5() As Byte
 bin5 = HexStringToBinary(src)
 Call COMP3_CNV_RTN((bin5), 5)
と書いておりますが、もしもこれを
 Dim bin5() As Byte
 bin5 = HexStringToBinary(src)
 Call COMP3_CNV_RTN(bin5, 5)
にしてしまうと、コンパイルエラー『ByRef 引数の型が一致しません。』が表示されることになります。

Command2 の方についても、変数 MOTO のデータ型が String では無かった場合
(たとえば、Dim MOTO As Variant や Dim MOTO() As Byte だった場合)において
同様にコンパイルエラー『ByRef 引数の型が一致しません。』が表示されます。

しかし引数が、ByVal で宣言されていれば、上記のコンパイルエラーになることなく
動作させることができます。その分、利用する際にも使いやすくなると思いますよ。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。