Click here to Skip to main content
15,902,447 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
Hello,

I want to pass a structure between VB (screen (form)) and VC++ (DLL), but it doesn't work...
Can i ask for your help? I want to borrow your wisdom, so let me ask you a question.
Sorry for my poor English.

First of all, it was originally developed with Visual Studio 6.0, and it was decided to convert the screen and DLL that were working stably, and I used the upgrade wizard function of Visual Studio 2008.
We understand that maintenance is required after use.

All warnings and errors were resolved, and after the build was completed, we checked the operation and proceeded with the maintenance of the parts that differed from the original operation. Among them, when I tried to refer to the structure that should have been edited by VC++ (DLL) in some processes on the VB side, I noticed that there was no data.
Maybe because of my lack of experience, I can't solve, and I can't get out of the problem.
My combination may be wrong.

Detailed information is provided below.



**Environment**
 <Development Environment>
  VisualStudio2008(VB、VC++)
  ※Convert what was developed with Visual Studio 6.0 with the upgrade wizard function,
   We are in the process of converting.
  Windows7 32bit

  <Execution Environment>
  Windows7 32bit



**Application Specification**
I would like it to work in the order 1 ⇒ 4.
  1. Pass search condition x 1, repeat count x 1, empty structure x 1 from VB (screen (form)) to VC++ (DLL).
  2. VC++ (DLL) searches the DB using the search condition as a key, and sets the search result in the structure passed from VB.
   ※With fetch, loop processing is performed for the number of iterations, and multiple records of information are obtained and set in the structure.
  3. Return the structure set in 2 and the processing result (return code) to VB.
  4. From the processing result (return code) received in 3, determine whether the VC++ processing is normal or abnormal,
   If it is normal, the data of the structure is displayed on the screen.



**Problem Details**
Based on the above "Application Specifications", we will explain the specific operations.
  In Stage 1, processing continues normally. (It is not possible to confirm whether it is the passed structure itself ...)
  As in stage 2, processing continues normally. I was able to edit the structure defined by VC++ (DLL).
  At stage 3, the process appears to have continued normally. At least the processing result returned normally.
  Stage 4 discovers that the structure is empty, even though the processing results are correct.
   Sadly, the result is "nothing on the screen".

In the preceding process (SELECT COUNT(*)) that is executed without any problems, there is no problem with the DB connection and SQL, and the value that is the processing result can be passed between VB and VC++.
Considering the difference from the preceding processing, I think there is a problem with the structure reference, but I don't have a solution...





**Program Source**
I will post the source of some applications as much as possible.
Comments are in Japanese. (Only important parts are translated into English.)

**<VB (screen (form))>**
**①API_Refer.vb**
VB
'' Function
 Public 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
'' Structure array declaration
Public dtpPS_NonDet() As tpPS_Det2 'POS外情報明細

'' 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  ←Problem spot! !
   Dim dtpPS_Gaisho As tpPS_Gaisho   ' Detail structure3
End Structure

        Public Structure tpPS_Det2
          Dim sShoriFlg As String           ' 処理フラグ(POS外情報明細テーブル)
          Dim sSrvNo As String              ' 管理番号(POS外情報/買廻明細テーブル)
          Dim sPosNo As String             ' POS通番/PC端末番号(POS外情報/買廻明細テーブル)
          Dim sTuuban As String            ' 取引通番(POS外情報/買廻明細テーブル)
          Dim sToriDate As String           ' 日付(POS外情報明細テーブル)
          Dim sToriTime As String           ' 時刻(POS外情報明細テーブル)
          Dim sKingaku As String            ' 買上金額(POS外情報/買廻明細テーブル)
          Dim sRiyuCd As String             ' 理由コード(POS外情報明細テーブル)
          Dim sSrvRank As String            ' サービスランク(POS外情報明細テーブル)
          Dim sAddSrvRank As String     ' 付加サービスランク(POS外情報明細テーブル)
          Dim sSrvTime As String            ' 規定サービス時間(POS外情報明細テーブル)
          Dim sChgTime As String          ' 変更サービス時間(POS外情報明細テーブル)
          Dim sHanbaiinCd As String      ' 係員コード(POS外情報/買廻明細テーブル)
          Dim sCustKbn As String           ' 顧客区分(POS外情報明細テーブル)
          Dim sKozaNo As String            ' 口座番号(POS外情報/買廻明細テーブル)
          Dim sKozaSbh As String           ' 口座種別(POS外情報/買廻明細テーブル)
End Structure




**③frmWork1.vb**
VB
        ''' strPrkSrvNum is the value entered from the screen.
Private NPosRecCnt As Integer ' Number of repetitions
    ~
            ''' Function of "Number of repetitions"
            Ret = Esql_NonPosCount(strPrkSrvNum, NPosRecCnt) ←"Number of repetitions"(NPosRecCnt)(No Problem)
            If Ret <> 0 Then
                ''' Error handling
                Exit Function
            Else
                ''' If "Number of repetitions" is greater than 1
                If NPosRecCnt > 0 Then
                    ''' Get information from DB.
                    ReDim dtpPS_GotData(0).dtpPS_NonDet(NPosRecCnt - 1)
                    Ret = Esql_SelNonPosDetail(strPrkSrvNum, NPosRecCnt, dtpPS_GotData(0).dtpPS_NonDet)  ←Problem spot! !
                    If Ret <> 0 Then
                        ''' Error handling
                        Exit Function
                    Else
                        ''' Display data from a structure to the screen.





**<VC++(DLL)>**
**④esql_com.h**
C++
typedef struct {
 BSTR szSyoriFlg;        // 処理フラグ(0:処理無し、1:追加処理、2:削除処理)
 BSTR szServiceNo;        // 管理番号
 BSTR szPosNo;                // POS通番/PC端末番号
 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**
C++
//@============================================================================
//@ Esql_SelNonPosDetail
//@ Get information from DB
//@
//@ 引 数: IN char* lpszSrvNumber : Parking ticket number
//@ IN long* nIndexNum                      :"Number of repetitions"(NPosRecCnt)
//@ OUT LPSAFEARRAY* pNposDet   :Structure(tpPS_Det2)
//@ 戻り値: = 0          :Normal End
//@                 > 0                                  :Error(SQLSTATE)
//@============================================================================
__declspec(dllexport) int __stdcall Esql_SelNonPosDetail(char *lpszSrvNumber, long *nIndexNum, LPSAFEARRAY *pNpos_Det)
{
long lRet, lCount;
int ii;
int nSqlstate;                                           // SQL return value (hexadecimal)
char *work;                                             // Work Area
NPOS_DET2 npos;                                  // [For structure reference]
LPSAFEARRAY psa = *pNpos_Det;         // [For structure reference]
int idx[1], lb, ub;                                     // [For structure reference]
static char bufa[1024];                           // [For structure reference]
static wchar_t bufw[1024];                     // [For structure reference]
size_t          buft;                                    // 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 );
}

// Setting for structure reference
//================================
// [For structure reference] Reference setting (start)
setlocale(LC_ALL,"");
SafeArrayLock(psa);
SafeArrayGetLBound(psa, 1, &lb);
SafeArrayGetUBound(psa, 1, &ub);
idx[0] = lb;

// 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;

// [For structure reference] Reference setting (get)
SafeArrayGetElement(psa, &idx[0], &npos);

// Edit data retrieved from DB 1
if (SQL_HY01 != -1)  strncpy_s(bufa,sizeof(bufa), SQL_SYORIFLG, 2);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szSyoriFlg);
npos.szSyoriFlg = SysAllocString(bufw);

// Edit data retrieved from DB 2
strncpy_s(bufa, sizeof(bufa),SQL_KANRINO, 16);
        mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szServiceNo);
npos.szServiceNo = SysAllocString(bufw);

// Edit data retrieved from DB 3
strncpy_s(bufa, sizeof(bufa),SQL_POSNO, 6);
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szPosNo);
npos.szPosNo = SysAllocString(bufw);

// Edit data retrieved from DB 4
strncpy_s(bufa, 6,SQL_SEQNO, 6);
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szSeqNo);
npos.szSeqNo = SysAllocString(bufw);

// Edit data retrieved from DB 5
strncpy_s(bufa, sizeof(bufa),SQL_DATE, 10);
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szCreateDate);
npos.szCreateDate = SysAllocString(bufw);

// Edit data retrieved from DB 6
strncpy_s(bufa, sizeof(bufa),SQL_TIME, 6);
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szCreateTime);
npos.szCreateTime = SysAllocString(bufw);

// Edit data retrieved from DB 7
if (SQL_HY07 != -1)  wsprintf(bufa, "%d", SQL_LNGSALMO);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szSalMoney);
npos.szSalMoney = SysAllocString(bufw);

// Edit data retrieved from DB 8
strncpy_s(bufa, sizeof(bufa),SQL_RIYUCD, 4);
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szRiyuCode);
npos.szRiyuCode = SysAllocString(bufw);

// Edit data retrieved from DB 9
if (SQL_HY09 != -1)  strncpy_s(bufa, sizeof(bufa),SQL_RANK, 4);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szServiceRank);
npos.szServiceRank = SysAllocString(bufw);

// Edit data retrieved from DB 10
if (SQL_HY10 != -1)  wsprintf(bufa, "%d", SQL_LNGSRVTIME);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szServiceTime);
npos.szServiceTime = SysAllocString(bufw);

// Edit data retrieved from DB 11
if (SQL_HY11 != -1)  wsprintf(bufa, "%d", SQL_LNGCHGTIME);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szChangeTime);
npos.szChangeTime = SysAllocString(bufw);

// Edit data retrieved from DB 12
if (SQL_HY12 != -1)  strncpy_s(bufa, sizeof(bufa),SQL_TANTOCD, 10);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szTantoCode);
npos.szTantoCode = SysAllocString(bufw);

// Edit data retrieved from DB 13
if (SQL_HY13 != -1)  strncpy_s(bufa, sizeof(bufa),SQL_CUSTKBN, 4);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szCustKubn);
npos.szCustKubn = SysAllocString(bufw);

// Edit data retrieved from DB 14
if (SQL_HY14 != -1)  strncpy_s(bufa, sizeof(bufa),SQL_KOZANO, 27);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szKozaNo);
npos.szKozaNo = SysAllocString(bufw);

// Edit data retrieved from DB 16
if (SQL_HY15 != -1)  strncpy_s(bufa, sizeof(bufa),SQL_KOZATYPE, 4);
else                 *bufa = 0x00;
mbstowcs_s(&buft, bufw, sizeof(bufw), bufa, 1024);
SysFreeString(npos.szKozaType);
npos.szKozaType = SysAllocString(bufw);

// [For structure reference] Reference settings (Settings)
SafeArrayPutElement(psa, &idx[0], &npos);    ←Editing to "npos" works fine.  SAFEARRAY structure can not be used in .net?
idx[0]++;  // Next Record
}


SQL_NOT:
// Cursol Close
//================================
EXEC SQL CLOSE NONPOS_CUR1;
EXEC SQL COMMIT WORK;

// Deallocation for structure reference
//================================
// [For structure reference] Reference setting (end)
SafeArrayUnlock(psa);

// 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     */
SafeArrayUnlock(psa);                                          /*[For structure reference] Reference setting (end)*/
return ( nSqlstate );                                              /* Abnormal termination of processing  */
}






Sorry for the long message.
Thank you.

What I have tried:

I have confirmed that the processing on the VC++ (DLL) side is being executed.

I know I'll need marshalling on the VB side, but I don't know how to combine it...

●「ByRef dtpPS_Det() As tpPS_Det2」→ ???
VB
Public Declare Function Esql_SelNonPosDetail Lib "Esql_Dll.dll" (ByVal SrvNum As String, ByRef RecordCnt As Long, ByRef dtpPS_Det() As tpPS_Det2) As Integer
Posted
Updated 14-Nov-22 21:04pm
v3

Quote:
I think COM will always works well,
that is, VB calls a C++ COM method which has only VARIANT/BSTR/base types (SHORT, long, etc.) arguments.
 
Share this answer
 
Comments
Marino_Y0301 14-Nov-22 5:52am    
Thanks for any help.

Perhaps I'm not making enough effort, but I haven't been able to find an effective solution for linking VC++ and VB.NET using "LPSAFEARRAY"...

VC++ seems to work fine except for "SafeArrayPutElement(psa, &idx[0], &npos);". (If you try to display "psa" in a message box after "SafeArrayPutElement(psa, &idx[0], &npos);", nothing will be displayed, so it seems to be empty...)

Is it difficult to display with MessageBox ( NULL, psa, TEXT ("TEST psa"), MB_OK)? (Sorry for the beginner's question)
Marino_Y0301 15-Nov-22 2:50am    
Thank you for the other day!
Your hint helped me.

I solved it with the program source that will be posted later. However, I'm wondering if it's better to specify a GUID. (Either way, the purpose of the processing can be achieved. It is the place commented (//~) in the structure definition of the program source.)
We also want to avoid unnecessary definitions, as there are several other functions that need similar modifications. Please lend me your wisdom.
longjmp 15-Nov-22 22:11pm    
Glad to hear you solved the problem, I also wrote an example to show how to pass it, at the time I didn't have VS2008 and an OS that supported it, I have since downloaded and deployed these on a VM. I'm guessing that your solution perhaps does something very similar to using the COM approach perhaps (data packaging and unpackaging, and perhaps calling some sort of COM proxy/stub interface). Your solution looks more concise than mine, and if it all works the same, maybe no additional GUIDs would be best? Just my guess, I'm not familiar with VB.NET, thank you, I learned a good trick too.

My COM Sample: http://ladder.42web.io/src/CppSvc.zip
Marino_Y0301 16-Nov-22 3:46am    
I'm appreciate to your kindness.
I see your example, and I learned how to use GUID.
Thanks for the example, it was very easy to understand. I will use it as a reference.
I am very grateful.
Maybe you can try changing the ByRef into ByVal, see example here:
Accessing Unmanaged Code from Managed Code[^]

For an example of marshalling, see: Passing Strings Between Managed and Unmanaged Code[^]
(sadly not in VB.NET but C#)
Also note the use of:
CharSet = CharSet.Ansi
 
Share this answer
 
v3
Comments
Marino_Y0301 11-Nov-22 3:02am    
Thank you!


But sorry, I made a mistake in writing the following program.

Correctly:

 **①API_Refer.vb**
 '' Function
Public Declare Function Esql_SelNonPosDetail Lib "Esql_Dll.dll" _
(ByVal SrvNum As String, ByRef RecordCnt As Long, ByRef dtpPS_Det() As tpPS_Det2) As Integer



Unfortunately, even after changing ByRef to Byval, there was no data in dtpPS_Det (structure tpPS_Det2).
It should have been edited from VC++, but I don't know why...


Do I need "MarshalAs" when calling from VB? Since the VC++ side treats it as "LPSAFEARRAY", should I pass it as a pointer?


If you have any idea, please help me.
Marino_Y0301 14-Nov-22 5:40am    
Hi,
I tried marshalling, but no luck.

<What I tried>
ByRef → ByVal
:Calling VC++ gives no error, but the struct passed from VB does not contain any data.

<out(), marshalas(unmanagedtype.safearray,="" safearraysubtype:="VarEnum.VT_ARRAY)" byval="" byref~="">
:There is no error when calling VC++, but an error occurs when referencing the struct passed from VB in subsequent processing.

<out(), marshalas(unmanagedtype.safearray)="" byval="" byref~="">
:In the case of "ByVal", an error occurred when calling VC++. In the case of "ByRef", an error occurred when referring to the structure in subsequent processing after calling VC++.

<out() byval="" byref~="">
:In the case of "ByVal", calling VC++ gives no error...but the struct passed from VB does not contain any data.In the case of "ByRef", an error occurred when referring to the structure in subsequent processing after calling VC++.

Is there something wrong with my marshalling? So far, passing structs "ByVal" seems to work better.
Marino_Y0301 15-Nov-22 2:41am    
Thank you for your help a few days ago!

As a result of various considerations, marshalling the structure on the VB side and treating it as an LPARRAY instead of a SAFEARRAY on the VC++ side worked well.
I will post the answer later.

Your advice helped me.
I'm really thankful to you!
RickZeeland 15-Nov-22 8:37am    
Ah finally, a satisfied customer!
:)
I really appreciate your kindness!

As a result, I was able to solve the problem by making the following corrections.



<VB (screen (form))>
①API_Refer.vb
VB
<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
'' 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
Ret = Esql_SelNonPosDetail(strPrkSrvNum, NPosRecCnt, dtpPS_GotData(0).dtpPS_NonDet)




<VC++(DLL)>
④esql_com.h
C++
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
C++
__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 /
}



Thanks to you, I can sleep in peace from now on.
I will deepen my skills and study so that I can help someone, like you!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900