トップ «前の日記(2008-07-08) 最新 次の日記(2008-07-10)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2008-07-09

_ GainerX

途中だけど、とりあえずここまでかな。

GainerX(2014/7/30 レポジトリをGitHubへ移動)

最初、オーバーラップトIOのみで1バイト単位のReadFileを利用していたが、アナログ/デジタル連続リードをかけると取りこぼしやすいことがわかったので、ComEventを利用してできる限り一括してReadFileをかけるようにした。ほぼ取りこぼしはなくなっている(VB6の場合)。

VS2008になっても、相変わらず、SAFEARRAY周りの処理が腐っているので絶望した。きっとこのまま直さないままATLはフェーズアウトしていくのかも。

たとえば、IDLで、[in]SAFEARRAY(byte) data と書いたものが、自動生成した接続ポイント(しかし、VC6の頃と比べて使われるのを拒否するかのように、わけのわからない場所に移動してしまって見つけるのにえらく苦労した。ヘルプの書き方もあいまいなのだが、クラスビューでCComCoClassを継承したクラスのコンテキストメニューの追加から行う)ではSAFEARRAY byte * dataとなるとか。*の数も間違えていたような気もするが、とにかく、内部型名を引数リストに残してはだめだろ。VC6の頃はここまでひどくはなかったような気がするが覚えてないや。 もっとも、SAFEARRAYを使っているところはIID変えずにいきなり変えてしまうかも。

それとは別にWin32OLEのSAFEARRAYの処理も少し気になる点があったり、いろいろ。VB版はそこそこ動くので、たぶん、Win32OLEの何かを突いてしまったのかも知れない。

あと、Gainer自身についてもリブートとKONFIGURATION後に挟むウェイトがどうも幅があって、そこらへんが難しい。

Rubyではこんなのがタイミングに依存しているが、動くときがある(ただし、SAFEARRAYの部分に問題がありそうで、デジタル信号が0/1ではなくnilになっている。

require 'win32ole'
 
gainer = WIN32OLE.new('GainerX.Gainer')
event = WIN32OLE_EVENT.new(gainer, '_IGainerEvents')
event.on_event('ButtonPressed') do 
  puts 'button pressed'
end
event.on_event('ButtonReleased') do
  puts 'button released'
end
event.on_event('DigitalInputs') do |switches|
  p switches
end
gainer.open 'COM3'
sleep 2
puts 'open comm'
gainer.Configuration = 1
sleep 3
gainer.LED = true
gainer.ReadAllDigitalInputs true
gainer.wait 15000
gainer.LED = false
sleep 1
gainer.close

実行すると

C:\home\test>ruby gainer.rb
open comm
[nil, nil, nil, nil]
[nil, nil, nil, nil]
button pressed
button released
[nil, nil, nil, nil]

_ 配列とポインタの違い

なんかはやっているから、もっと教育的にわかりやすい例を考えてみた。
#include 
typedef void (*fn)();
void ary_rtn(char* p)
{
    p -= 8;
    (*(fn*)p)();
}
void ptr_rtn(char* p)
{
    p -= 8;
    (*(fn*)p)();
}
void array()
{
    char a[] = "1234";
    ary_rtn(a);
}
void pointer()
{
    char* p = "1234";
    ptr_rtn(p);
}
int main(int argc, char* argv[])
{
    array();
    printf("array\n");
    fflush(stdout);
    pointer();
    printf("pointer");
    fflush(stdout);    
    return 0;
}
配列は戻ってこられるが、ポインタは逝ってしまう。もちろん最適化をしてはいけない。
で、教育的な配慮として、これを示したあとに「このようにポインタは危険です。だからポインタではなく配列を利用しましょう」と続ける。
VC++8では、さすがにこれは通用しなかった(ちゃんと数えてないが16バイトくらいの緩衝領域を確保しているようにみえるので、そのサイズを求めればできるはずだけど)。VC6やgccだけ。

_ 配列とポインタの違い

まじめに説明することを考えてみる。多分、ょゎさんの「概念」の話は、上の例とかみたいに、文字列実体(上の例だと0x30〜0x340x00)をどこに確保するかではなく、aとかpの値そのものではないかと思うので、その線。
#include 
int main(int argc, char* argv[])
{
    char a[] = "1234";
    char* p = "1234";
    char** v = &a;    // 型違いなので警告が出る
    printf("%08X\n", *v);
    v = &p;
    printf("%08X\n", *v);    
    return 0;
}
一度、その変数(ここでは配列のaと、ポインタのp)のアドレスを取り、その中身そのものを表示する。
c:\home\test>ap2
34333231
00407038
配列の場合は、文字列の実体そのものが値として格納されていることが(エンディアンの問題があると後で気づくが、ちょっとしょうがないな)、ポインタでは、どこかのアドレスが値として格納されていることが見える。
で、この後に、続けて
    v = &p;
    printf("%c\n", **v);
は'1'を出力するけど(上の例だと00407038が文字列のアドレスだということを示せる)、
   v = &a;
   printf("%c\n", **v);
は、実行すると死んでしまうことを示すとか(というか、34333231と出てきているところにリトルエンディアンとはとかさらに混乱のネタがあるようにも思うが)。
このへんのところが、逆におれにはわかりにくて、最初のころはポインタばかり使っていたのだった。
本日のツッコミ(全4件) [ツッコミを入れる]
_ suke (2008-07-09 23:11)

うーん。配列の要素の型をWin32OLE側でちゃんと認識できずに変換できないからnilになっているとか。そんな単純な話じゃないですよね。

_ arton (2008-07-09 23:17)

SafeArrayPtrOfIndexの使い方の問題だと思いますが、どう使うのが正しいのかわからないので、僕も調べてみます。

_ arton (2008-07-10 00:52)

あ、なんかわかったような。戻り値の変換は正しいです(今、検証した)。イベントの引数なので何かが違うみたいです(これから確認します)。

_ arton (2008-07-10 01:19)

すみません。僕の設定ミスです。VBは気をきかせて(というよりも、SafeARrayPtrOfIndexを使っていないのだと思う)うまく処理していただけでした。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|

ジェズイットを見習え