VBからDLL(VC)を呼び出すと戻り値が不正

このQ&Aのポイント
  • VCで作成したDLLをVBから呼び出すと、正常な値が取得できない問題が発生しています。
  • VCの単体実行では正常な値が取得できていることを確認済みですが、VBの戻り値として取得すると不正な値が返ってきます。
  • 解決策をご存知の方は教えていただけないでしょうか。
回答を見る
  • ベストアンサー

VBからDLL(VC)を呼び出すと戻り値が不正

お世話になります。 VCで作成DLLをVBでCallし戻り値を取得していますが 正常にとれません。 VCを単体で実行すると「9.999999」というformatで 値が入っている事は確認済みですがVBの戻り値として 取得した場合「-9.25596288973593E+61」となってしま います。 ご存知の方ご教授頂けないでしょうか。 ******* Cソース ****** /*cpu使用率取得関数*/ double GetCpuUsage() { HQUERY hQuery; HCOUNTER hCounter; PDH_RAW_COUNTER Counters[COUNTERS_SIZE]; PDH_STATISTICS Statistics; int CurrentCounter; int CurrentNum; double CpuUsage; PdhOpenQuery(NULL, 0, &hQuery); PdhAddCounter(hQuery, "\\Processor(0#0)\\% Processor Time", 0, &hCounter); PdhCollectQueryData(hQuery); PdhGetRawCounterValue(hCounter, NULL, &Counters[0]); CurrentCounter = 1; CurrentNum = 2; Sleep(1000); PdhCollectQueryData(hQuery); PdhGetRawCounterValue(hCounter, NULL, &Counters[CurrentCounter]); CurrentCounter++; if(CurrentCounter >= COUNTERS_SIZE) CurrentCounter = 0; PdhComputeCounterStatistics( hCounter, PDH_FMT_DOUBLE, (CurrentNum < COUNTERS_SIZE) ? 0 : CurrentCounter, CurrentNum, Counters, &Statistics); CpuUsage = Statistics.max.doubleValue; printf("CpuUsage:%.02f%\n", CpuUsage); PdhCloseQuery(hQuery); /* CPU使用率を戻り値にセットする。 */ return CpuUsage; } ****** VBソース ****** Option Explicit Private Declare Function GetCpuUsage Lib "C:\GetCpuUsage.dll" Alias "_GetCpuUsage@0" () As Double Private Sub Command1_Click() Dim ret As String Dim ret2 As Long ret = GetCpuUsage() MsgBox ret End Sub

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

えーっと、私、勘違いしているかも。。。 > VCを単体で実行すると「9.999999」というformatで これは単に format という話で、C側ソースの "printf("CpuUsage:%.02f%\n", CpuUsage);" の結果は、 "CpuUsage:-92559628897359297000000000000000000000000000000000000000000000.00" となるということですね??Σ(・ε・;) これら2つ数値は、表示形式こそ違うものの、値は同一です。(C側ソースの "%.02f" を "%g" に変えると、 XXE+YY の形式で表示されると思います) MsgBox にて、数字の羅列形式で表示する方法なんですが、、、ちょっとすぐにはわかりません。 申し訳ないです。。

yamataro25
質問者

お礼

kocha1979さん お礼を言うのが遅くなり大変すいません。 初心者の私には勉強になりました。 結果的には解決できませんでしたが 取り合えずVBでWMIを使用し実装しました。 ありがとうございました。

その他の回答 (2)

回答No.3

No.2に対する自己補足です。(;´Д`) > VCで作成DLLをVBでCallし戻り値を取得していますが > 正常にとれません。 関数の戻り値は正常にとれていて、C側"printf"関数での表示と、VB側"MsgBox"関数での表示で、表示形式が異なっているだけかと思われます。

回答No.1

> VBの戻り値として取得した場合「-9.25596288973593E+61」となってしまいます。 とは、メッセージボックスでの表示でしょうか?? 質問が微妙に曖昧ですが、試してみました。 環境は VisualStudio .NET 2003 Pro --- DLL側 --- BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } extern "C" __declspec(dllexport) double GetCpuUsage(void) { double CpuUsage = 9.999999; return CpuUsage; } --- VB側 --- Public Class Form1 Inherits System.Windows.Forms.Form Private Declare Function GetCpuUsage Lib "CPUUsage.dll" Alias "GetCpuUsage" () As Double (中略) Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim ret As String ret = GetCpuUsage() MsgBox(ret) End Sub End Class 結果は、メッセージボックスに正しく 9.999999 と表示されますね。

yamataro25
質問者

お礼

KOCHA1973さん、アドバイス有難うございます。 環境を記載しておりませんでした申し訳ありません。 環境は、VisualStudio6.0です。 私もKOCHA1973さんと同様にC側の関数戻り値に 9.999999とセットした場合は正常にうまくいく 事を確認できました。 但し、Statistics.max.doubleValueの値を戻り値 にセットするとうまくいきません。 VB側で確認したというのはメッセージボックスで 確認しました。 Statistics.max.doubleValueの値はVB側では受け 取れないのでしょうか? 現在、VB側ではStringで受け取ろうとしており ますが、Double型でも同様の事象が発生しており ます。 Statistics.max.doubleValueで取得した値が 受け渡し可能かどうかご存知ないでしょうか。

関連するQ&A

  • VC++で作成したDLLをVBから呼ぶと戻り値が化けてしまう

    はじめまして。いつも勉強させていただいております。 VCは今回初めてやっておりますので当たり前の質問 になってしまうかもしれませんがご教授願います。 以下のような仕様でものづくりを行っております。 1.VBよりVC++で作成したDLLを呼び出す。 2.VC++で作成したDLL側ではパラメータより取得した   値を元に足し算をした結果を   戻り値にセットして要求元に返却する。 といった流れで考えています。 2の部分についてはExeを一度作成し実行させた ところDOS窓に値が表示されました。(printfで) しかし、正しくOUTPUTされた値がVB側の戻り値と して返却された時点で参照すると「-6348」 となっています。 なぜこうなってしまうのか原因がわからず投稿 させて頂きました。 ご存知の方、ご教授下さい。 ************************************************* VC++ DLL側のソース ************************************************* #include <windows.h> #define DLL_EXPORT __declspec(dllexport) extern "C" { DLL_EXPORT int add(int a,int b); } int add(int a,int b) { return a+b; } ************************************************* VB  DLL呼び出し元 ************************************************* Option Explicit Private Declare Function add Lib "C:\Program Files\Microsoft Visual Studio\test\Debug\test.dll" Alias "_add@8" (a As Long, b As Long) As Integer Private Sub Command1_Click() Dim ret As Long ret = add(1, 2) MsgBox ret End Sub 環境 OS:WinXP 言語:VC++6.0    VB6.0(SP6)

  • VB6で作成したDLLをVC6で使用する方法

    VB6で作成したDLLをVC6で使用できなくて困っています。 以下にトライしたことを示します。 (1) VB6でTRUEを返すだけの関数を入れたActiveX DLLを作成 (2) VC6のLoadLibraryに成功(戻り値がNULL以外) (3) VC6のGetProcAddressに失敗(戻り値がNULL) (4) VC.NET付属のDumpbinユーティリティでは(1)で作成した関数が表示されない。 何が悪いのでしょうか。 宜しくお願いします。

  • 文字列を返すVCで作成したDLL関数をVBで呼ぶと...

    VC++で文字列を返すDLL関数を作成しました。 LPCSTR GetVcString(void) これをVBでStringとして受け取り、MsgBoxで表示すると正常に取得できているようなのですが、Lenで文字数を取得すると変な値が返ってきます。 1. Dim Ret As String 2. Ret=GetVcString() 3. MsgBox(Ret) ← VCで返された文字列は正常に表示されている 4. MsgBox(Str(Len(Ret))) ← 実際の文字数とはかけ離れた数値になる 2行目と3行目の間に、 Ret=Left(Ret,InStr(Ret,vbNullChar)-1) を噛ませれば文字数は正常な値になるのですが、このような処理をしなくても正常に文字数を取得する方法があれば教えてください。

  • DLL VBとC++

    VBAからVC++2005のDLLを呼び出すプログラムを書いています。 VB側で作成したcpp_proc関数を呼ぶとVBアプリ自体が落ちました。 DLLのreturnの直前に以下のMessageBoxで表示させるとそこまでは表示され、 リターンを押すと、落ちました。 VB側の引数の値 String * 8192が悪いのでしょうか? return直前まで動作していたので、DLLの戻り値に何か原因があるのでしょうか? ついでの質問ですが、DEFの @1は無くても動くのでしょうか? 意味が知りたいです。 // ----- C++ (DLL側) ----- int __stdcall cpp_proc(LPCSTR inp, LPSTR out) { ... 省略 MessageBox(0, "ここまで通過", "debug", MB_OK); return 0; } // ----- DEF ----- LIBRARY "example" DESCRIPTION 'テスト' EXPORTS ; 明示的なエクスポートはここへ記述できます cpp_proc @1 '----- VB側 ----- Public Declare Function cpp_proc Lib "example.dll" _ (ByVal inp As String, ByRef out As String) As Integer Public Sub Test() Dim ret As Integer Dim inp As String Dim out As String * 8192 ret = cpp_proc(inp, out) MsgBox("ret=[" & Cstr(ret) & "]"); End Sub

  • 引数で戻り値を取得するプログラム

    以下のように、引数で戻り値を取得するプログラムを書きたいのですが どのように書けば正しいでしょうか? VB6とVB2005の両方の書き方を教えてください。 sub kekka(byval src as string, byref dst() as string) dim ret() as string ret(0) = "abc" ret(1) = "efg" kekka = ret end sub kekka("xxx", dat() ) msgbox(dat(0)) msgbox(dat(1))

  • VC6.0で作成したDLLでVBからの配列を受け取る方法

    VC++でDLLを作成しています。 VBから呼び出しで、配列を渡し、その配列の値を VCで使用したいのです。 通常変数でテストして、うまくいっているのですが、 配列に変更したところ、値がうまく渡りません。 どなたかお分かりになられる方いらっしゃいましたら お力をお貸し願えないでしょうか? 変数で成功しているプログラム VB6.0 標準モジュール Declare Function fncTest Lib "fncTest.dll" (a As Long) As Long フォーム Private Sub Test_Click() dim i as integer i = fncTest(1) End Sub VC++6.0 fncTest.h fncTest_API int _stdcall fncTest(int); fncTest.cpp fncTest_API int _stdcall fncTest(int a) { a = a+1; return a; } fncTest.def     省略 変数aを配列に変更して作ってみたもの(配列bにVBからの配列aの値を入れようとしていますが、 うまくいっていません。) VB6.0 標準モジュール Declare Function fncTest Lib "fncTest.dll" (ByRef a() As Long) As Long フォーム Private Sub Test_Click() Dim i As Integer Dim hairetu(7) As Long Dim values As Variant For i = 0 To 7 hairetu(i) = i Next i values = fncTest(hairetu()) End Sub VC++6.0 fncTest.h fncTest_API int _stdcall fncTest(int*); fncTest.cpp fncTest_API int _stdcall fncTest(int* a) { int b[7]; int i; for (i = 0;i <= 7;i++){ b[i] = a[i]; } return 0; } 以上よろしくお願いします。

  • FindWindowの戻り値が違う!?

    いつもお世話になっております。 FindWindowの戻り値についてご教授願います。 ret = FindWindow(NULL,"sample"); 上記を実行した場合、取得する画面がアクティブの時と非アクティブの時でFindWindowの戻り値が違うのは何故でしょうか? 私は、sample画面が非アクティブでもアクティブ状態の時と同じハンドルが取得したのですが、良い方法は有りますでしょうか? 取得画面タイトル:sample 実行ファイル名:sample.exe 実行環境:WindowsXP 開発環境:VC++ 6.0

  • VB2005でVC6.0で作成したDLLから値を取得するには

    VB6からVB2005にコンバートをしたのですがVCで作成したDLLの関数の箇所で下記エラーが出てしまいました。(VCのDLLは他で使用の為変更できず。) エラー内容 「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。」 いろいろサイト等を調べたのですがうまくいきません。 Marshal.AllocCoTaskMem、Marshal.Copyなどを使用すればできるらしいのですが難しすぎて挫折しました。。 どなたかご教授下さい。 よろしくお願い致します。 VC側ソース(XXX.DLL) GetData( unsigned char far *pRec,   //データ short int *pRecLen,  //サイズ { Char cbBuf[1024]; //バッファ memset(cbBuf, ' ', 1024); //初期化 Call GetBuf(cbBuf); memcpy(pRec, cbBuf, *pRecLen); return(0) ; } VB2005のソース <StructLayout(LayoutKind.Sequential)> Structure St Dim A () As Byte Dim B () As Byte End Structure Declare Function GetData Lib "XXX.DLL" (Byref RecData As St , ByRef Reclen As Short) As Short Sub Dim TmpData As St Dim TmpLen As short =100 Dim X As Byte Dim Y As Byte Redim TmpData.A(49) Redim TmpData.B(49) Call GetData(TmpData, TmpLen) X =TmpData.A(0) Y =TmpData.B(1) ・ ・ End Sub

  • VB6からVCで作成したDLLへのvoidポインタの受け渡し

    VB6でVCで作成されたDLLの関数から戻り値としてvoidポインタを受け取り、 それをDLLの別の関数を呼び出す際に引数として渡すプログラムを作成しようとして 詰まっています。以下サンプルです。 ===VB側 Public Type Param   sStr As String   lNum As Long End Type Declare Function Create Lib "test.dll" (ByRef tParam As Param) As Long Declare Function Free Lib "test.dll" (ByVal pSt As Any) As Long Dim pSt As Long Dim lRet As Long Dim tParam As Param With tParam   .sStr = "test" & Chr(0)   .lNum = 10 End With pSt = Conn(tParam) lRet = Free(pSt) ===VC側 typedef struct stParaA {   char * aaa;   char * bbb; } PARAM_A; typedef struct stParaB {   char * ccc;   int iNum; } PARAM_B; extern "C" void * __stdcall Create(PARAM_B* stParaB) {   PARAM_A stParaA;   //stParaAの各メンバ領域をMallocで確保   return((void*)stParaA); } extern "C" int __stdcall Free(void* stParaA) {   //stParaAの各メンバ領域をfree   return 0; //正常終了の場合 } VC側でデバッグしてみたところ、stParaBの各メンバの値はVC側で取得できているので、 DLLの呼び出し自体には問題はないようですが、Create()でreturnする時と、Free()に 入ってきたときではstParaAのアドレスが変わってしまい、異常終了します。 VC側はソースはあるのでデバッグは可能なのですが、DLLの修正自体は不可となって いるため、VB側を直すしかないのですが、どのようにすればアドレスの受け渡しが できるのでしょうか。

  • VCのDLLを呼ぶ場合の宣言方法

    VB.NetからVC++で作成したDLLを使用する場合の宣言方法について教えてください。 VC++のDLLの関数で引数に構造体のポインタを渡すようになっているのですがマーシャリング属性の指定方法がわからなく困っています。 VB6.0では使用できたのでDLL側は問題ないと思うので(DLL側は修正ししないでVB側の修正で対応したいです)VB.Net側の問題だと思うのですがどこを直したらいいのかご教授願えないでしょうか。 以下にVC++のDLLの宣言部、VB6.0のときのソース、VB.Netのソースの必要と思われる部分を載せておきます。 ただしVB.NetのソースはVB6.0からUpGradeしたものをWeb等で調べて修正したものです。 当方VBに関してはまだ触り始めて1ヶ月も経っていないのですが仕事で急ぎで対応しなくてはならないため勉強する時間がなくどうすればいいか困っています。 よろしくお願いします。 ### VC++側ソース(概略) void __stdcall GetData( STESTDATA* pData ) struct STESTDATA { float fData1[6]; float fData2[32][6]; }; ### VB6.0の時のソース Private Type testdata Data1(5) As Single Data2(5, 31) As Single End Type Private Declare Sub GetData Lib "TestLib.dll" (ByRef pData As testdata) Private Sub TimerGetData_Timer() Dim data As testdata GetData data End sub ### VB.Net(2008)の時のソース <StructLayout(LayoutKind.Sequential)> _ Private Structure testdata <MarshalAs(UnmanagedType.ByValArray)> Dim Data1() As Single <MarshalAs(UnmanagedType.ByValArray)> Dim Data2(,) As Single Public Sub Initialize() ReDim Data1(5) ReDim Data2(5, 31) End Sub End Structure <System.Runtime.InteropServices.DllImport("TestLib")> _ Private Shared Sub GetData(ByVal pData As testdata) End Sub Private Sub TimerGetData_Tick(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles TimerGetData.Tick Dim data As testdata data.data1 = New Single(5) {} data.data2 = New Single(5, 31) {} data.Initialize() GetData(data) End Sub ※因みにVB.Netのソースを実行すると本来ならdata構造体のdata1とdata2に値にDLL内で値が設定されるのですが、現状では全て0が設定されてしまっています。

専門家に質問してみよう