こんにちは。
ここの利用は初めてです。不慣れな点がありましたら申し訳ありません。
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をVBからVC++に渡す。
- VC++は、検索条件をキーにしてDBを検索し、検索結果をVBから渡された構造体に設定する。※fetchでループ処理を行い、複数の情報を構造体に設定する。
- 2 で設定した構造体と処理結果を VB に返す。
- 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); 97・ 98・ 99・ 100// 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}
よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/11/15 07:32 編集
2022/11/15 07:47
2022/11/15 09:17