HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2014
0205
RLDLL(C言語)による文字列の受け渡し13解決


RL

リンク

2014/2/5(Wed) 21:49:39|NO.59701

とあるプログラムを作っている最中に複雑な文字列処理が必要になりました
HSPで実現しようと思ったのですがあまりにも遅すぎるので実用的ではありませんでした
そこでDLLを利用し高速化しようとしたのですがあいにくDLLは門外漢でうまくできません

なんとかWebの情報を見て整数や浮動点小数などは受け渡しできるようになったのですが
文字列の受け渡しはいくら試しても何らかの問題がでてしまいます
一番うまくいったかと思うコードを載せてみますので問題点を指摘して頂けないでしょうか

C言語側

IDE : Visual Studio Express 2013

プロジェクト設定(変更点) :
文字セット(マルチバイト文字セットに)
ランタイムライブラリ(マルチスレッド(/MT))

ヘッダーファイル内、"dllmain.h"
#ifdef  _MAKE_DLL_
# define __PORT __declspec(dllexport) /* DLLを作る場合 */ #else # define __PORT __declspec(dllimport) /* DLLを使う場合 */ #endif __PORT char MyFunction(char*);

ソースファイル内、"dllmain.c"
#define     _MAKE_DLL_
#define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "dllmain.h" #include "string.h" __PORT char MyFunction(char *buff) { char *buf = strcat(buff, buff); return *buf; }



HSP側
#uselib "DLL.dll"
#cfunc MyFunction "MyFunction" sptr buff = "STRING" mes MyFunction(buff)


このコードで実現したい挙動は"STRING"を2倍にして"STRINGSTRING"と表示することです
実際にVCでビルドした際には全くエラーは出ませんがHSPファイルのあるフォルダに
できたDLLを移してHSPコードを実行するとフリーズしてしまいます



この記事に返信する


悲しみのチンフェ

リンク

2014/2/5(Wed) 22:33:14|NO.59703

HSP側のソースを

#uselib "DLL.dll" #cfunc MyFunction "MyFunction" sptr buff = "STRING\0 " mes MyFunction(buff)
にして実行してみるとドウですか?



RL

リンク

2014/2/5(Wed) 22:40:13|NO.59704

>悲しみのチンフェ様

試しましたがだめみたいでした…
挙動は変わらずフリーズのままでした

ですが配列長を確保するというのは忘れていました、ありがとうございます



MillkeyStars

リンク

2014/2/5(Wed) 23:51:20|NO.59705

DLL 側で、受け入れた char *buff のアドレスが違っているような・・・


a="" mes ""+varptr(a)

と DLL 側の char *buff のアドレスが一致しないと、DLL側で内容を書き換えできないと思うけど。
HSP の方を、変数として呼び出してやってみてね。

#cfunc MyFunction "MyFunction" var



.

リンク

2014/2/6(Thu) 01:47:54|NO.59709

DLL側 (test.cpp)
#include <stdio.h>
#include <string.h>
#define EXPORT extern "C" __declspec (dllexport)
EXPORT int MyFunction(char s1[]){
strcat(s1,s1);
return 0;
}

HSP側
#uselib "test.dll"
#func MyFunction "MyFunction" var

s1="abc"
MyFunction s1
mes s1

MyFunctionの戻り値はstatに入る。

DLLは32bitでコンパイルしないといけない...はず。
(HSPから64bitのDLLは呼び出せない(はず))



悲しみのチンフェ

リンク

2014/2/6(Thu) 03:11:49|NO.59711

hspsdkいじったほうがはやいと思う。
hsp3のフォルダの中に作成できるプロジェクトあるからそれ改造したほうが楽かも



f(始業中)

リンク

2014/2/6(Thu) 08:34:49|NO.59713

DLLに渡すのにはsptrで良い。

sptrは変数でも直文字列でも良いのでそのままでは相手に渡せない。
一度HSPが文字列分のメモリを確保して、文字列内容をその領域にコピーして
そのポインタをDLLに渡してくれる。(多分(ヲ)

だからsptrで受け取ろうとすると、
HSPが用意した領域に返事を書いてしまい失敗する。


DLLで処理して欲しいバッファのポインタを渡すならvar。
こっちは「変数」のポインタを相手に直渡ししてくれる。



check

リンク

2014/2/6(Thu) 13:31:46|NO.59718

フリーズする原因は
char *buf = strcat(buff, buff);
の行だろうな。
何も指していない(メモリが確保されていない)ポインタbufに、
値を無理矢理詰め込もうとしている状態。

.氏が言っているように関数を以下のように書き直すか、
・C

_PORT void MyFunction(char buf[]) { strcat(buf, buf) }
・HSP

#uselib "DLL.dll" #func MyFunction "MyFunction" var ...(省略)
またはメモリを動的に確保するという手段もあるが、
速度重視ならこの方法はお勧めできない。



Humi

リンク

2014/2/6(Thu) 13:46:38|NO.59719

渡す前にmemexpandしなくていいんですかね。
まだ64byte行ってないからいいものの、文字列の長さによっては
ダイアログでてきますよランタイムのw

C/C++ならすんなりかけるんですけどね(--;)
Cだけはちょっと
いっつもdefファイル通してやってたので、、



Humi

リンク

2014/2/6(Thu) 14:07:41|NO.59720


#uselib "test.dll" #func MyFunction "MyFunction" var
これをsptrで書いてたから問題が起きてたんでしょう?
const char にいれようとすればそりゃエラー起きますよ。
sptr はあくまで読み取り専用ですよ。
読み書きするときは変数のアドレスを
varptr か #funcをvar にするかで

あと buf[] も *buf も一緒では?
&buf とか **buf とか buf は別ですけど、

char *buf = strcat(buff, buff);

これは何も指してない buf に代入後の buff のアドレスを代入しているので エラーにはならないはず、、



denko

リンク

2014/2/6(Thu) 15:23:34|NO.59722

なんかいろんな意見がでてよくわからない状況になってるので
他の人とかぶる点もありますが気づいた点をまとめておきます。

#cfunc MyFunction "MyFunction" sptr
と定義していますのでDLLのMyFunctionに渡されるのはHSP側の変数buffのアドレスではなく
HSPが用意したbuffのコピーのアドレスです。
このコピーのサイズは変数buffのサイズに関係なく文字列の長さ分しか確保されないので
strcatを実行する時点で領域外に書き込んでエラーになってると思われます。
MyFunction内で十分なメモリを確保してそこにコピーしてから作業するか
#cfunc MyFunction "MyFunction" var
と定義しておけばHSP側の変数buffのアドレスを渡せるので、あらかじめbuffに十分領域を確保しておいてけば大丈夫です。


strcatではコピー元とコピー先を同じにしたばあいの動作は未定義なので本当は良くないです。
実際には問題なく動くみたいですが。

mes MyFunction(buff)
となってますが通常のDLLで直接文字列を返す関数は作れませんので変数に文字列を受けとるしかできません。
直接文字列を返す関数を作るにはHSP専用のプラグインを作成する必要があります。
作り方はhspdskとかに載ってます。



RL

リンク

2014/2/6(Thu) 20:41:08|NO.59730

みなさま回答有難うございます!
C言語では避けて通れない道なのでしょうがやはりメモリやポインタはややこしいですね…
精進します

最後に、実際に私が成功したコードを載せておきますね

ただ、コピー元とコピー先が同一の場合、strcatの動作が未定義のせいなのか様々な文字列を
指定した時に一部の文字列でエラーになるので渡した文字列に"DLL"を付け加える動作になっています
(2倍にする動作はただの例で実際にやりたいコードではないので)



C/C++側 ソースファイル(dllmain.cpp)

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>

#define EXPORT extern "C" __declspec (dllexport)

EXPORT int MyFunction(char s1[]){
strcat(s1, "DLL");
return 0;
}

ヘッダファイル 無し



HSP側

#uselib "DLL.dll"
#func MyFunction "MyFunction" var

buff = "DLL"
memexpand buff,128 //文字列の長さに応じて変更
MyFunction buff
mes buff



arx

リンク

2014/2/7(Fri) 08:26:12|NO.59732

既に解決済みとのことですが、出来れば遅いと判断するに至った元のHSPコードを載せませんか?
strf一回で済むところをstrmidやら何やら大量に使ってたりというのは、Cにおいてもsprintfとstrcatでありがちなことなので、
もしかしたらHSP上でも十分な処理なのでは…と思った次第です。
strfも決して軽い処理ではありませんが、何度も命令呼ぶよりは軽いはずですので。



RL

リンク

2014/2/8(Sat) 11:21:35|NO.59756

>arx様
お気遣いありがとうございます
ですが少々載せるには長すぎるので載せることができません、ごめんなさい
構文解析をするプログラムだ、とだけ



ONION software Copyright 1997-2023(c) All rights reserved.