質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VC++

VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

1143閲覧

VBからVC++に構造体を渡し、VC++で編集してVBに返す方法

Marino_Y

総合スコア2

VC++

VC++ (Visual C++) とは、Microsoft製のC++のための統合開発環境です。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

1グッド

1クリップ

投稿2022/11/14 03:18

こんにちは。
ここの利用は初めてです。不慣れな点がありましたら申し訳ありません。
VB(画面(フォーム))とVC++(DLL)の間で構造体を渡したいのですが、どうにもうまくいかず困ってしまいました...
知恵をお借りしたいです。

経緯

元々Visual Studio 6.0で開発し安定稼働していたアプリケーション(画面とDLL)を、この度Windows10への移行に伴いVB/VC++2019にコンバージョンすることになりました。
第一段階としてVisual Studio 2008のアップグレードウィザード機能を利用しました。

現状

VB、VC++それぞれのワーニングやエラーは全て解消しました。
ビルド完了後、動作確認を行いながら元々の動作と異なる部分のメンテナンスを進める中で、VB側からVC++を呼び出す処理(DBからSELECTした結果をVBに返す)で、構造体にデータが1件も入らないことに気がつきました。
MicrosoftのQ&AやCODE PROJECTで構造体を値で渡す(ByVal)やマーシャリング(MarshalAs)をすすめられたのですが、私の組み合わせが悪いのか、解決できずにおります。

詳細情報を記載します。

環境

<開発環境>

  •   VisualStudio2008(VB、VC++)
  •   Windows7 32bit

<実行環境>

  •   Windows7 32bit
  •   接続先DB(SymfowareServer / WindowsServer2003R2)

仕様

できれば元々の仕様どおり1⇒4の順番で動作させたいです。(最終的に同じ結果が得られるのであればOK)

  1. 検索条件×1、繰り返し回数×1、空の構造体×1をVBからVC++に渡す。
  2. VC++は、検索条件をキーにしてDBを検索し、検索結果をVBから渡された構造体に設定する。※fetchでループ処理を行い、複数の情報を構造体に設定する。
  3. 2 で設定した構造体と処理結果を VB に返す。
  4. 3で受け取った処理結果から、VC++の処理が正常かを判断し、構造体からデータを画面に表示する。

先行処理(SELECT COUNT(*))では、DB接続やSQLに問題はなく、値のみですが受け渡しができていることを確認しました。(VBからは同じVC++の別の関数を呼び出しています。DB接続処理は共通です。)
以上のことから考えると、問題は構造体であろうことは間違いなさそうなのですが・・・

プログラムソース

<VB (screen (form))>
①API_Refer.vb

VB.NET

1Public Declare Function Esql_SelNonPosDetail Lib "Esql_Dll.dll" (ByVal SrvNum As String, ByRef RecordCnt As Long, ByRef dtpPS_Det() As tpPS_Det2) As Integer

②mdlPKSrv.vb

VB.NET

1'' Structure array declaration 2Public dtpPS_NonDet() As tpPS_Det2 'POS外情報明細 3 4'' Structure definition (VB side) 5Public Structure tpPS_GotData 6Dim dtpPS_Hed As tpPS_Hed ' Structure for header 7Dim dtpPS_KaiDet() As tpPS_Det2 ' Detail structure1 8Dim dtpPS_NonDet() As tpPS_Det2 ' Detail structure2  ←問題の構造体 9Dim dtpPS_Gaisho As tpPS_Gaisho ' Detail structure3 10End Structure 11 12Public Structure tpPS_Det2 13 Dim sShoriFlg As String 14 Dim sSrvNo As String 15 Dim sPosNo As String 16 Dim sTuuban As String 17 Dim sToriDate As String 18 Dim sToriTime As String 19 Dim sKingaku As String 20 Dim sRiyuCd As String 21 Dim sSrvRank As String 22 Dim sAddSrvRank As String 23 Dim sSrvTime As String 24 Dim sChgTime As String 25 Dim sHanbaiinCd As String 26 Dim sCustKbn As String 27 Dim sKozaNo As String 28 Dim sKozaSbh As String 29End Structure

③frmWork1.vb

VB.NET

1''' strPrkSrvNum is the value entered from the screen. 2Private NPosRecCnt As Integer ' Number of repetitions 3    ~ 4''' Function of "Number of repetitions" 5Ret = Esql_NonPosCount(strPrkSrvNum, NPosRecCnt) ←ここは問題なし 6If Ret <> 0 Then 7''' Error handling 8Exit Function 9Else 10''' If "Number of repetitions" is greater than 1 11If NPosRecCnt > 0 Then 12''' Get information from DB. 13ReDim dtpPS_GotData(0).dtpPS_NonDet(NPosRecCnt - 1) 14Ret = Esql_SelNonPosDetail(strPrkSrvNum, NPosRecCnt, dtpPS_GotData(0).dtpPS_NonDet)  ←問題の箇所(VC++(DLL)呼び出し) 15If Ret <> 0 Then 16''' Error handling 17Exit Function 18Else 19''' Display data from a structure to the screen.

<VC++(DLL)>
④esql_com.h

VC++

1typedef struct { 2 BSTR szSyoriFlg; 3 BSTR szServiceNo; 4 BSTR szPosNo; 5 BSTR szSeqNo; 6 BSTR szCreateDate; 7 BSTR szCreateTime; 8 BSTR szSalMoney; 9 BSTR szRiyuCode; 10 BSTR szServiceRank; 11 BSTR szAddSrvRank; 12 BSTR szServiceTime; 13 BSTR szChangeTime; 14 BSTR szTantoCode; 15 BSTR szCustKubn; 16 BSTR szKozaNo; 17 BSTR szKozaType; 18} NPOS_DET2;

⑤Esql_com.sc

VC++

1__declspec(dllexport) int __stdcall Esql_SelNonPosDetail(char *lpszSrvNumber, long *nIndexNum, LPSAFEARRAY *pNpos_Det) 2{ 3long lRet, lCount; 4int ii; 5int nSqlstate; // SQL return value (hexadecimal) 6char *work; // Work Area 7NPOS_DET2 npos; // [For structure reference] 8LPSAFEARRAY psa = *pNpos_Det; // [For structure reference] 9int idx[1], lb, ub; // [For structure reference] 10static char bufa[1024]; // [For structure reference] 11static wchar_t bufw[1024]; // [For structure reference] 12size_t buft; // Work Area 13 14// 15// Processing start setting 16// 17EXEC SQL SET TRANSACTION READ ONLY, 18ISOLATION LEVEL READ UNCOMMITTED; // Transaction start setting 19 20//* 21// Remove trailing whitespace from a string 22//========================== 23strrtrim(lpszSrvNumber); 24 25// Setting of Parking ticket number 26//================================ 27strcpy_s(SQL_VARNUMBER.sqlvar,32, lpszSrvNumber); 28SQL_VARNUMBER.sqllen = strlen(SQL_VARNUMBER.sqlvar); 29strcpy_s(SQL_NUMBER,32, lpszSrvNumber); 30 31// Get the number of records 32//================================ 33if ( ( lRet = Esql_NonPosCount( SQL_NUMBER, &lCount ) ) != 0 ) { 34return ( lRet ); 35} 36 37// Check the number of acquisitions and area allocation 38//================================ 39if ( *nIndexNum < lCount ) { 40return ( -1 ); 41} 42 43// Setting for structure reference 44//================================ 45// [For structure reference] Reference setting (start) 46setlocale(LC_ALL,""); 47SafeArrayLock(psa); 48SafeArrayGetLBound(psa, 1, &lb); 49SafeArrayGetUBound(psa, 1, &ub); 50idx[0] = lb; 51 52// Cursor declaration 53//================================ 54EXEC SQL WHENEVER SQLERROR GOTO :SQL_ERROR; 55EXEC SQL DECLARE NONPOS_CUR1 CURSOR FOR 56SELECT SHORIFLG, SRVNO, POSNO, TUUBAN, 57TORIDATE, TORITIME, KINGAKU, RIYUCD, 58SRVRANK, SRVTIME, CHGTIME, HANBAIINCD, 59CUSTOMKBN, KOZANO, KOZASBH 60FROM PSSCH.NONPOSDET 61WHERE SRVNO = :SQL_VARNUMBER; 62 63// Cursor Open 64//================================ 65EXEC SQL OPEN NONPOS_CUR1; 66 67// Get data from DB 68//================================ 69EXEC SQL WHENEVER NOT FOUND GOTO :SQL_NOT; 70for ( ii = 0; ii < lCount; ii++ ) { 71EXEC SQL FETCH FROM NONPOS_CUR1 72INTO :SQL_SYORIFLG INDICATOR :SQL_HY01, 73:SQL_KANRINO INDICATOR :SQL_HY02, 74:SQL_POSNO INDICATOR :SQL_HY03, 75:SQL_SEQNO INDICATOR :SQL_HY04, 76:SQL_DATE INDICATOR :SQL_HY05, 77:SQL_TIME INDICATOR :SQL_HY06, 78:SQL_LNGSALMO INDICATOR :SQL_HY07, 79:SQL_RIYUCD INDICATOR :SQL_HY08, 80:SQL_RANK INDICATOR :SQL_HY09, 81:SQL_LNGSRVTIME INDICATOR :SQL_HY10, 82:SQL_LNGCHGTIME INDICATOR :SQL_HY11, 83:SQL_TANTOCD INDICATOR :SQL_HY12, 84:SQL_CUSTKBN INDICATOR :SQL_HY13, 85:SQL_KOZANO INDICATOR :SQL_HY14, 86:SQL_KOZATYPE INDICATOR :SQL_HY15; 87 88// [For structure reference] Reference setting (get) 89SafeArrayGetElement(psa, &idx[0], &npos); 90 91// Edit data retrieved from DB 1 92if (SQL_HY01 != -1) strncpy_s(bufa,sizeof(bufa), SQL_SYORIFLG, 2); 93else *bufa = 0x00; 94mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024); 95SysFreeString(npos.szSyoriFlg); 96npos.szSyoriFlg = SysAllocString(bufw); 979899100// Edit data retrieved from DB 15 101if (SQL_HY15 != -1) strncpy_s(bufa, sizeof(bufa),SQL_KOZATYPE, 4); 102else *bufa = 0x00; 103mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024); 104SysFreeString(npos.szKozaType); 105npos.szKozaType = SysAllocString(bufw); 106 107// [For structure reference] Reference settings (Settings) 108SafeArrayPutElement(psa, &idx[0], &npos); ←ここが問題? 109idx[0]++; // Next Record 110} 111 112 113SQL_NOT: 114// Cursol Close 115//================================ 116EXEC SQL CLOSE NONPOS_CUR1; 117EXEC SQL COMMIT WORK; 118 119// Deallocation for structure reference 120//================================ 121// [For structure reference] Reference setting (end) 122SafeArrayUnlock(psa); 123 124// End processing 125//========================== 126return ( 0 ); 127 128 129 130// DB Error Handling 131//========================== 132SQL_ERROR: 133EXEC SQL WHENEVER SQLERROR CONTINUE; / SQL Error disable setting / 134nSqlstate = strtol(SQLSTATE,&work,16); / SQL Return value setting / 135EXEC SQL CLOSE NONPOS_CUR1; / Cursol End / 136EXEC SQL ROLLBACK WORK; / SQL Rollback processing / 137SafeArrayUnlock(psa); /[For structure reference] Reference setting (end)/ 138return ( nSqlstate ); / Abnormal termination of processing / 139}

よろしくお願いいたします。

Marino_Y👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

SAFEARRAYで構造体をやりとりするのはすごい面倒なんで、単なるLPARRAYとしたほうがいいですよ。

vb

1Public Structure tpPS_Det2 2 <MarshalAs(UnmanagedType.BStr)> Dim sShoriFlg As String 3 <MarshalAs(UnmanagedType.BStr)> Dim sSrvNo As String 4... 5End Structure 6 7<DllImport("Esql_Dll.dll")> 8Public Function Esql_SelNonPosDetail(ByVal SrvNum As String, RecordCnt As Integer, <Out()> dtpPS_Det() As tpPS_Det2) As Integer 9End Function 10 11 Ret = Esql_NonPosCount(strPrkSrvNum, NPosRecCnt)  12 ReDim dtpPS_GotData(0).dtpPS_NonDet(NPosRecCnt - 1) 13 Ret = Esql_SelNonPosDetail(strPrkSrvNum, NPosRecCnt, dtpPS_GotData(0).dtpPS_NonDet)

c++

1__declspec(dllexport) int __stdcall Esql_SelNonPosDetail(const char *srv, int lCount, NPOS_DET2 *dets) 2{ 3 for( int idx = 0; idx<lCount; idx++){ 4 dets[idx].sShoriFlg = SysAllocString(L"a1"); 5 dets[idx].sSrvNo = SysAllocString(L"a2"); 6... 7 } 8}

投稿2022/11/14 11:56

matukeso

総合スコア1590

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Marino_Y

2022/11/15 07:32 編集

ご回答ありがとうございます。 実に的確なアドバイスでした! 私のやりたいことを汲み取って、SAFEARRAYに代わる方法を教えてくださり深く感謝しております!! 最終的に、下記で問題解決できました。 _<VB (screen (form))>_ **①API_Refer.vb** ```VB.NET <DllImport("Esql_DLL.dll", CharSet:=CharSet.Ansi)> _ Public Function Esql_SelNonPosDetail(ByVal SrvNum As String, ByRef RecordCnt As Long, <Out()> ByVal dtpPS_Det() As tpPS_Det2) As Integer End Function ``` **②mdlPKSrv.vb** ```VB.NET '' Structure array declaration Public dtpPS_NonDet() As tpPS_Det2 '' Structure definition (VB side) Public Structure tpPS_GotData Dim dtpPS_Hed As tpPS_Hed ' Structure for header Dim dtpPS_KaiDet() As tpPS_Det2 ' Detail structure1 Dim dtpPS_NonDet() As tpPS_Det2 ' Detail structure2 Dim dtpPS_Gaisho As tpPS_Gaisho ' Detail structure3 End Structure //<ComVisible(True), Guid("1D93560B-39AF-41cb-9E11-74F8E5A96199")> _ <StructLayout(LayoutKind.Sequential)> _ Public Structure tpPS_Det2 <MarshalAs(UnmanagedType.BStr)> Dim sShoriFlg As String <MarshalAs(UnmanagedType.BStr)> Dim sSrvNo As String <MarshalAs(UnmanagedType.BStr)> Dim sPosNo As String <MarshalAs(UnmanagedType.BStr)> Dim sTuuban As String <MarshalAs(UnmanagedType.BStr)> Dim sToriDate As String <MarshalAs(UnmanagedType.BStr)> Dim sToriTime As String <MarshalAs(UnmanagedType.BStr)> Dim sKingaku As String <MarshalAs(UnmanagedType.BStr)> Dim sRiyuCd As String <MarshalAs(UnmanagedType.BStr)> Dim sSrvRank As String <MarshalAs(UnmanagedType.BStr)> Dim sAddSrvRank As String <MarshalAs(UnmanagedType.BStr)> Dim sSrvTime As String <MarshalAs(UnmanagedType.BStr)> Dim sChgTime As String <MarshalAs(UnmanagedType.BStr)> Dim sHanbaiinCd As String <MarshalAs(UnmanagedType.BStr)> Dim sCustKbn As String <MarshalAs(UnmanagedType.BStr)> Dim sKozaNo As String <MarshalAs(UnmanagedType.BStr)> Dim sKozaSbh As String End Structure ``` **③frmWork1.vb** ```VB.NET Ret = Esql_SelNonPosDetail(strPrkSrvNum, NPosRecCnt, dtpPS_GotData(0).dtpPS_NonDet) ``` _<VC++(DLL)>_ **④esql_com.h** ```VC++ typedef struct {  BSTR szSyoriFlg;  BSTR szServiceNo;  BSTR szPosNo;  BSTR szSeqNo;  BSTR szCreateDate;  BSTR szCreateTime;  BSTR szSalMoney;  BSTR szRiyuCode;  BSTR szServiceRank;  BSTR szAddSrvRank;  BSTR szServiceTime;  BSTR szChangeTime;  BSTR szTantoCode;  BSTR szCustKubn;  BSTR szKozaNo;  BSTR szKozaType; } NPOS_DET2; ``` **⑤Esql_com.sc** ```VC++ __declspec(dllexport) int __stdcall Esql_SelNonPosDetail(char *lpszSrvNumber, long *nIndexNum, NPOS_DET2 *pNpos_Det) { long lRet, lCount; int ii; int nSqlstate; // SQL return value (hexadecimal) char *work; // Work Area int idx[1], lb, ub; // [For structure reference] static char bufa[1024]; // [For structure reference] static wchar_t bufw[1024]; // [For structure reference] static size_t st; // Work Area // // Processing start setting // EXEC SQL SET TRANSACTION READ ONLY, ISOLATION LEVEL READ UNCOMMITTED; // Transaction start setting //* // Remove trailing whitespace from a string //========================== strrtrim(lpszSrvNumber); // Setting of Parking ticket number //================================ strcpy_s(SQL_VARNUMBER.sqlvar,32, lpszSrvNumber); SQL_VARNUMBER.sqllen = strlen(SQL_VARNUMBER.sqlvar); strcpy_s(SQL_NUMBER,32, lpszSrvNumber); // Get the number of records //================================ if ( ( lRet = Esql_NonPosCount( SQL_NUMBER, &lCount ) ) != 0 ) { return ( lRet ); } // Check the number of acquisitions and area allocation //================================ if ( *nIndexNum < lCount ) { return ( -1 ); } // Set locale, idx //================================ setlocale(LC_ALL,""); idx[0] = 0; // Cursor declaration //================================ EXEC SQL WHENEVER SQLERROR GOTO :SQL_ERROR; EXEC SQL DECLARE NONPOS_CUR1 CURSOR FOR SELECT SHORIFLG, SRVNO, POSNO, TUUBAN, TORIDATE, TORITIME, KINGAKU, RIYUCD, SRVRANK, SRVTIME, CHGTIME, HANBAIINCD, CUSTOMKBN, KOZANO, KOZASBH FROM PSSCH.NONPOSDET WHERE SRVNO = :SQL_VARNUMBER; // Cursor Open //================================ EXEC SQL OPEN NONPOS_CUR1; // Get data from DB //================================ EXEC SQL WHENEVER NOT FOUND GOTO :SQL_NOT; for ( ii = 0; ii < lCount; ii++ ) { EXEC SQL FETCH FROM NONPOS_CUR1 INTO :SQL_SYORIFLG INDICATOR :SQL_HY01, :SQL_KANRINO INDICATOR :SQL_HY02, :SQL_POSNO INDICATOR :SQL_HY03, :SQL_SEQNO INDICATOR :SQL_HY04, :SQL_DATE INDICATOR :SQL_HY05, :SQL_TIME INDICATOR :SQL_HY06, :SQL_LNGSALMO INDICATOR :SQL_HY07, :SQL_RIYUCD INDICATOR :SQL_HY08, :SQL_RANK INDICATOR :SQL_HY09, :SQL_LNGSRVTIME INDICATOR :SQL_HY10, :SQL_LNGCHGTIME INDICATOR :SQL_HY11, :SQL_TANTOCD INDICATOR :SQL_HY12, :SQL_CUSTKBN INDICATOR :SQL_HY13, :SQL_KOZANO INDICATOR :SQL_HY14, :SQL_KOZATYPE INDICATOR :SQL_HY15; // Edit data retrieved from DB 1 if (SQL_HY01 != -1) strncpy_s(bufa,sizeof(bufa), SQL_SYORIFLG, 2); else *bufa = 0x00; mbstowcs_s(&st, NULL, 0, &bufa, 1024); mbstowcs_s(&st, &bufw[0], st, &bufa, 1024); if (pNpos_Det[idx[0]].szSyoriFlg != NULL) SysFreeString(pNpos_Det[idx[0]].szSyoriFlg); pNpos_Det[idx[0]].szSyoriFlg = SysAllocString(bufw); ・ ・ ・ // Edit data retrieved from DB 15 if (SQL_HY15 != -1) strncpy_s(bufa, sizeof(bufa),SQL_KOZATYPE, 4); else *bufa = 0x00; mbstowcs_s(&st, NULL, 0, &bufa, 1024); mbstowcs_s(&st, &bufw[0], st, &bufa, 1024); if (pNpos_Det[idx[0]].szKozaType != NULL) SysFreeString(pNpos_Det[idx[0]].szKozaType); pNpos_Det[idx[0]].szKozaType = SysAllocString(bufw); idx[0]++; // Next Record } SQL_NOT: // Cursol Close //================================ EXEC SQL CLOSE NONPOS_CUR1; EXEC SQL COMMIT WORK; // End processing //========================== return ( 0 ); // DB Error Handling //========================== SQL_ERROR: EXEC SQL WHENEVER SQLERROR CONTINUE; / SQL Error disable setting / nSqlstate = strtol(SQLSTATE,&work,16); / SQL Return value setting / EXEC SQL CLOSE NONPOS_CUR1; / Cursol End / EXEC SQL ROLLBACK WORK; / SQL Rollback processing / return ( nSqlstate ); / Abnormal termination of processing / } ``` この度は助けてくださり本当に本当にありがとうございました!!
matukeso

2022/11/15 07:47

vcはintもlongも32bitだけど、vb.netのlongは64bitてすよ。
Marino_Y

2022/11/15 09:17

追加のご指摘ありがとうございます。 元々vcもvbも6.0の時はlongだったので全く疑っていませんでした・・・。 だからintで回答をくださっていたのですね。 vb.netになってからの違いでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問