Quantcast
Channel: Visual C forum
Viewing all 15302 articles
Browse latest View live

Red lines but no compilation errors VS 2017

$
0
0

Greetings everyone.

Most of the code under development in my company is in c#, but I am responsible for an old dll written in c++.

We recently converted from VS2015 to VS2017. After switching over, I started getting lots of red squiggly lines, like so.

If I hover the cursor over one of the red lines I get "name followed by '::' must be a class or namespace name".

The code compiles and runs fine with no errors. But those red lines are annoying the bejesus out of me.

Does anyone know what the hell is going on and what I can do about it?


calling WPF function inside c++ from second thread

$
0
0

I want create process which will show result in to WPF after cycle. For instance, I want update progressbar after cycle inside loop.

I read this documentation https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/threading-model but I am not sure if I can call from second thread, inside unmanaged code, c# function, which update GUI.


How to check image type using resource ID?

$
0
0

I need to check image type before calling different functions to load images, the image can be either BITMAP or GIF, which are defined in the code below.

IDB_THICKNESSXY			GIF					"ThicknessXY_test.gif"
IDB_THICKNESSZ			BITMAP					"ThicknessZ.bmp

Could you please let me know how to check the image type using the resource ID?

Thanks in advance.

Cannot read from a file using std::wifstream

$
0
0

Hi,

I know a file uses 16 bit chars because I have seen it in the binary editor of Visual Studio 2017. So I am using std::wifstream to open it. However when I read with getline, I get garbage (bunch of symbols looking japanese or so).

Then I tried to imbue a facet like this:

std::wifstream in{ m_headerFile.c_str() };

// apply facet
in.imbue(std::locale(in.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));

and this worked (now I get wchar_t characters but no "japanese" symbols.

The problem is I don't know why I needed to imbue this facet and why this one in particular. It was sort of trial and error. I had expected that the reading of the file would be trivial but it wasn't. By the way, the file is a  text file (actually generated by Visual Studio 2017 when I created an MFC app), which is very strange...

Can someone explain to me what is happening here? Also, is there a way to ASK the fie to give you the encoding it uses so I can open it with the correct encoding?

See, I copy from this file to  another and when I try to compile the other as part of my solution, well I get problems like this:

warning C4335: Mac file format detected: please convert the source file to either DOS or UNIX format
1>c:\users\juan dent\source\repos\mfc\samplecformview\cviewsubclass.cpp(2): fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?

Thanks,

Juan


Juan Dent

LINK : fatal error LNK1104: cannot open file 'libcpmt.lib'

$
0
0

I am trying to use the Java Native Interface(JNI) to compile and run a simple program. I am following the steps found here: http://java.sun.com/docs/books/jni/html/start.html#27008

 

I have gone through the first several steps successfully.

1) I created a Java program with appropriate native methods

 

  •    public class HelloJNI
  • {
  •       private native void print();
  •       public static void main(String[] args)
  •       {
  •          new HelloJNI().print();
  •       }
  •       static
  •       {
  •          System.loadLibrary("HelloJNI");
  •       }
  •    }

2) I called javah -jni on my class file to create the C style header file

3) I wrote the implementation specified by the header in C++

 

  • #include <jni.h>
  • #include <iostream>
  • #include "HelloJNI.h"
  • using namespace std;
  • JNIEXPORT void JNICALL 
  • Java_HelloJNI_print(JNIEnv *env, jobject obj)
  • {
  •   cout << "Hello JNI!" << endl;
  •   return;
  • }
4) Now I am at the step when I need to compile the C++ file and generate the .dll
    I initially tried running this command: 
   cl
      -I"C:\Program Files\Java\jdk1.7.0\include"
-I"C:\Program Files\Java\jdk1.7.0\include\win32" -MD -LD HelloJNI.cpp
-FeHelloJNI.dll
   but when I ran this I got an error:
  C:\Program Files\Java\jdk1.7.0\include\jni.h(39) : fatal error C1083: Cannot open include file: 'stdio.h': No such file or directory
 
So the command I am trying to run now is:
cl
-I"c:/Program Files (x86)/Microsoft Visual Studio 9.0/Common7/IDE"
-I"c:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/include"
-I"c:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/lib"
-I"c:/Program Files/Java/jdk1.7.0/include" -I"c:/Program Files/Java/jdk1.7.0/include/win32"
-LD HelloJNI.cpp -FeHelloJNI.dll
And When I run this I get:
LINK : fatal error LNK1104: cannot open file 'libcpmt.lib'
Which doesn't make any sense to me beucause 'libcpmt.lib' is on my PATH variable and should be including in the cl command because I point -I to the directory it is in.
Has anyone encountered this issue? 
Any help would be great.
Thanks

 

 


Errors within powrprof.h, powersetting.h, and powerbase.h in Visual Studio 2017 Windows SDK Version 10.0.17134.0

$
0
0

I have errors within the headers mentioned in the title. The two files I have included are powrprof.h and powersetting.h with powerbase.h having errors within powrprof.h. Now, this isn't an issue with finding the files themselves because not only are they not underlined by intellisense, but they can also be found by searching in the explorer. I have tried changing the Windows SDK Version, I have tried repairing the latest version of the Windows SDK, I have tried numerous reboots, I have tried verifying the include paths, I have tried repairing VIsual Studio 2017 and there is nothing changing these errors. These errors started on a brand new project within VIsual Studio 2017 only when I included these header files. I have read here that there are undefined functions from Microsoft. Is this still the case? Will the workarounds in that thread work here, all the way in 2018? The last thing I have done is uninstall Visual Studio 2017 and then reinstall it, but I would like to avoid doing that.

Here is my error list and here is my build output. Now there should be two errors in there from the functions from the powerprof.h because they aren't defined, but the rest should be valid.

Thank you for your time.

Save the bitmap image after convert to 1 bit monochrome

$
0
0

Hi, Im using GDI+ to convert the bitmap pixel format from 24bit to 1 bit by using below code:

GdiplusStartupInput sti;                                                                // Initialize Gdiplus
    ULONG_PTR gpToken;
    int n = sizeof sti;
    GdiplusStartup(&gpToken, &sti, NULL);
    Bitmap* myBitmap = new Bitmap(Bitmap Path Name);                                    // Load the bitmap from the path name
    PixelFormat pxf = myBitmap->GetPixelFormat();
Gdiplus::ColorPalette* pal = (Gdiplus::ColorPalette*)malloc(sizeof(Gdiplus::ColorPalette) + 2 * sizeof(Gdiplus::ARGB));
        pal->Count = 2;
        pal->Flags = 0;
        Gdiplus::Bitmap::InitializePalette(pal, Gdiplus::PaletteTypeFixedBW, 2, FALSE, NULL);
        // Convert the bitmap pixel format to 1 bit monochrome (PixelFormat1bppIndexed)
        myBitmap->ConvertFormat(PixelFormat1bppIndexed, Gdiplus::DitherTypeErrorDiffusion, Gdiplus::PaletteTypeFixedBW, pal, 0);
        pxf = myBitmap->GetPixelFormat();

After convert the pixel format successfully, I'm facing the problem to save this altered bitmap image, can anyone please help me on this problem T.T

Thanks!

WSARecvFrom : Receive data into multiple buffers

$
0
0

Hello,

I'm using the following code in order to receive N_BUF UDP messages, each will be received to a different pointer. 

#define N_BUF 6
WSABUF DataBuf[N_BUF];
char RecvBuf[BUF_LEN * N_BUF];

for (int i=0;i<N_BUF;i++)
	{
		DataBuf[i].len = BUF_LEN;
		DataBuf[i].buf = &RecvBuf[i*BUF_LEN];
	}

rc = WSARecvFrom(RecvSocket,
			DataBuf,
			N_BUF,
			NULL,
			&Flags,
			(SOCKADDR *)& SenderAddr,&SenderAddrSize, &Overlapped, NULL);

Upon calling to WASRecvFrom + WaitForSingleObject (Am I right ?) with N_BUF buffers, how can I know what is the destination of the last message ?


Thank you,
Zvika 



Getting rid of atlTraceGeneral category shown in ATLTRACE output

$
0
0

Hi guys,

After upgrading to VS2013 I started receiving all my ATLTRACE2 messages in a "() : atlTraceGeneral - My output" format.

e.g.
ATLTRACE(_T("This is my data: %d\n"), 124);
is shown as
dllmain.cpp(1121) : atlTraceGeneral - This is my data: 124

I don't need this additional info with filename and line. Is here some way to get back to the previous format so that the output would be just:

This is my data: 124

Thank you

CreateWindow API is not working on VS2015..

$
0
0

Hello,

We are using CreateWindow() API which was working correctly on VS2012 before upgrading to VS2015. After upgrading to VS2015 CreateWindow API is returning null HWND.

We are calling AtlAxWinInit() before CreateWindow() API as shown below.

Eg:

// Code on VS2012 which is working correctly and failing on VS2015.

CreateControl()

{

      BOOL res = AtlAxWinInit();         // successfully return true..

      // Below API successfully return HWND on VS2012 level.

      HWND hwndChild =   CreateWindow(_T("AtlAxWin110"),
                                                                _T("test"),
                                                                WS_CHILD|WS_VISIBLE,
                                                                0,0,0,0,
                                                                hwnd,NULL,
                                                               ::GetModuleHandle(NULL),
                                                               NULL);

}

As per VS2015 we changed class name to "AtlAxWin140" still API is failing.

CreateControl()

{

      BOOL res = AtlAxWinInit();         // successfully return true..

      // For VS2015 we changed class name to "AtlAxWin140" still API is returning null HWND.

      HWND hwndChild =   CreateWindow(_T("AtlAxWin140"),
                                                                _T("test"),
                                                                WS_CHILD|WS_VISIBLE,
                                                                0,0,0,0,
                                                                hwnd,NULL,
                                                               ::GetModuleHandle(NULL),
                                                               NULL);

}

I also checked GetLastError() after CreateWindow calll; it is returning "Class is not registered".

Could you please help me to resolve this..

Thanks..

Interaction between OS Version, SDK Version, Framework Version and Redistributables Version

$
0
0

Hi,

our Applications have to support Windows 10, Windows 7 with SP1 and Windows Server 2012-2016.

At the Moment, all our applications are target to Windows SDK 8.1 and Platform Toolset v120.

We're installing .NET 4.7.1 and Microsoft Visual C++ 2013 Redistributable 12.0.21005 at our customer computers.

We develop in Visual Stduio 2013.

Now, we like to upgrade to Visual Studio 2017. When opening a solution, Visual Studio likes to upgrade the projects to Platfom Toolset v141 and wants to retarget the projects to 10.0.17134.0.

Now I have some questions

1) Waht is the "Platform Toolset" exactly?

2) Can the application with the new toolset and SDK run on the OS described obove (esspecialy Windows 7)?

2) Do I have to install a new Redistributable Package at our Customer Computer to be compatible with the new SDK version?

Thanks for your help!

Encrypted file with WinAPI CryptEncrypt , the Key is exists but forgot the cryptography method

$
0
0

i have an old unmanaged DLL from the old days of programming in VC++

now i need to use it again , this dll uses a license file which i set up its encryption with WinAPI cryptEncrypt/Decrypt functions , i remember the key , but i do not remember which cryptography method i've used !

unfortunately the source code is lost due to a HDD failure

now i need to use this DLL and need to decrypt its license file

do you guys have any suggestion ?

thanks in advanced

NTLM AcceptSecurityContext fails on remote machine, but works locally

$
0
0
I am trying to implement NTLM authentication in C++ using Windows API 

    InitializeSecurityContext
    AcquireCredentialsHandle
    AcceptSecurityContext

I implemented a server and a client which exchange the token generated using these functions. Everything works fine when I run server and client on the same machine, ... BUT as soon as I run the apps in 2 different machines ON THE SAME domain it does not work anymore.

To be precise the server call of <code>AcceptSecurityContext</code> fails with error <code>SEC_E_INVALID_TOKEN</code>.

Do you know what am I doing wrong?

Part of this code is taken from a WebServer. If I use INTERNET EXPLORER as client to connect from a remote machine works fin.

Is there anything I should check like Firewall or Networks security which prevents NTLM across 2 machines to work properly?

I am using <code>boost::asio</code> to exchange the tokens through the networks

Below The full listing. 

Once build is finished use command line 's' to start the server and 'c' to stat the client




            #pragma warning( disable: 4996 )

            #include <boost/asio.hpp>
            #include <boost/assert.hpp>
            #include <thread>

            #include <Windows.h>

            #define SECURITY_WIN32
            #include <Security.h>
            #include <cassert>
            #include <iostream>

            #define TARGET_INIT_SECURITY_CONTEXT "TEST/192.168.10.92"

            #define BYTES_MAX_MESSAGE            12000
            #define ASIO_BUFFER_SIZE             1024

            #define CLIENT_SECURITY_CONTEXT         "NTLM"
            #define CLIENT_SECURITY_REQUIREMENTS    ISC_REQ_CONNECTION

            #define SERVER_SECURITY_CONTEXT         "NTLM"
            #define SERVER_SECURITY_REQUIREMENETS   ASC_REQ_CONNECTION


            void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
            int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);

            std::string base64_decode(std::string const& encoded_string);
            std::string base64_encode(char const* bytes_to_encode, unsigned int in_len);


            class NTLMServer
            {
            public:
                std::string first_call(std::string clientToken_string)
                {
                    SECURITY_STATUS status = ::AcquireCredentialsHandle(NULL,
                        SERVER_SECURITY_CONTEXT,
                        SECPKG_CRED_INBOUND,            
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &serverCredentials_,
                        NULL);

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");        

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    SecBuffer serverOutBuffer_;
                    SecBufferDesc serverToken_;

                    serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                    serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                    serverOutBuffer_.pvBuffer = pOut;        

                    serverToken_.cBuffers = 1;
                    serverToken_.pBuffers = &serverOutBuffer_;
                    serverToken_.ulVersion = SECBUFFER_VERSION;

                    std::string out;        

                    SecBufferDesc clientToken;
                    SecBuffer clientOutBuffer;

                    {
                        std::string strToken = base64_decode(clientToken_string);            

                        BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                        std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                        strToken.copy(reinterpret_cast<char*>(pOut), strToken.size());

                        clientToken.cBuffers = 1;
                        clientToken.pBuffers = &clientOutBuffer;
                        clientToken.ulVersion = SECBUFFER_VERSION;

                        clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                        clientOutBuffer.cbBuffer = strToken.size();
                        clientOutBuffer.pvBuffer = pOut;

                        ULONG ContextAttributes = 0;

                        SECURITY_STATUS  status = AcceptSecurityContext(
                            &serverCredentials_,
                            NULL,
                            &clientToken,
                            SERVER_SECURITY_REQUIREMENETS,
                            SECURITY_NATIVE_DREP,
                            &hContext_,
                            &serverToken_,
                            &ContextAttributes,
                            NULL);

            
                        BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_OK, "AcceptSecurityContext failed");
            
                        int bufferSize = static_cast< int >(serverOutBuffer_.cbBuffer);
                        out = base64_encode(reinterpret_cast< const char *> (serverToken_.pBuffers->pvBuffer), bufferSize);
                    }

                    return out;
                }

                void second_call(const std::string& clientToken_string)
                {
                    SecBufferDesc clientToken;
                    SecBuffer clientOutBuffer;
        
                    std::string strToken = base64_decode(clientToken_string);        

                    BYTE       *pIn = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                    strToken.copy(reinterpret_cast<char*>(pIn), strToken.size());

                    clientToken.cBuffers = 1;
                    clientToken.pBuffers = &clientOutBuffer;
                    clientToken.ulVersion = SECBUFFER_VERSION;

                    clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                    clientOutBuffer.cbBuffer = strToken.size();
                    clientOutBuffer.pvBuffer = pIn;

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    SecBuffer serverOutBuffer_;
                    SecBufferDesc serverToken_;

                    serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                    serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                    serverOutBuffer_.pvBuffer = pOut;         

                    serverToken_.cBuffers = 1;
                    serverToken_.pBuffers = &serverOutBuffer_;
                    serverToken_.ulVersion = SECBUFFER_VERSION;

                    ULONG ContextAttributes = 0;

                    SECURITY_STATUS  status = AcceptSecurityContext(
                        &serverCredentials_,
                        &hContext_,
                        &clientToken,
                        SERVER_SECURITY_REQUIREMENETS,
                        SECURITY_NATIVE_DREP,
                        &hContext_,
                        &serverToken_,
                        &ContextAttributes,
                        NULL);
            
                    BOOST_ASSERT_MSG(status != SEC_E_INVALID_TOKEN, "Invalid Token!?!?!?");
                    BOOST_ASSERT_MSG(status == SEC_E_OK, "NOT OK?!?!?" );
                }

                CredHandle      serverCredentials_;
                CtxtHandle      hContext_;
            };

            class NTLMClient
            {
            public:
                std::string first_call()
                {
                    ULONG ContextAttributes = 0;
                    SECURITY_STATUS  status = AcquireCredentialsHandle(
                        NULL,
                        CLIENT_SECURITY_CONTEXT,
                        SECPKG_CRED_OUTBOUND,            
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &hCred_,
                        NULL);

        

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");

                    SecBuffer   OutSecBuff;

                    BYTE       *pIn = NULL;

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    BOOL   fDone = FALSE;
                    BOOL       *pfDone = &fDone;

                    DWORD       cbOut = BYTES_MAX_MESSAGE;
                    DWORD      *pcbOut = &cbOut;

                    OutDesc_.ulVersion = 0;
                    OutDesc_.cBuffers = 1;
                    OutDesc_.pBuffers = &OutSecBuff;

                    OutSecBuff.cbBuffer = *pcbOut;
                    OutSecBuff.BufferType = SECBUFFER_TOKEN;
                    OutSecBuff.pvBuffer = pOut;

                    status = InitializeSecurityContext(
                        &hCred_,
                        NULL,
                        TARGET_INIT_SECURITY_CONTEXT,
                        CLIENT_SECURITY_REQUIREMENTS,
                        0,
                        SECURITY_NATIVE_DREP,
                        NULL,
                        0,
                        &hContext_,
                        &OutDesc_,
                        &ContextAttributes,
                        NULL);

        

                    BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED, "InitializeSecurityContext failed");

                    *pcbOut = OutSecBuff.cbBuffer;
                    *pfDone = !((SEC_I_CONTINUE_NEEDED == status) ||
                        (SEC_I_COMPLETE_AND_CONTINUE == status));

        

                    std::string output;
                    output.resize(cbOut * 2);

                    cs_base64_encode(pOut, cbOut, &output[0]);
                    output.erase(output.find_first_of('\0'));  // remove the string
        
                    return output;
                }

                std::string second_call(const std::string& server_response)
                {        
                    SecBuffer   OutSecBuff;

                    BYTE       *pIn;
                    BYTE       *pOut;

                    DWORD       cbOut = 0;
                    DWORD      *pcbOut = &cbOut;

                    BOOL        done;
                    DWORD       cbIn;

                    pIn = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    int what_is_this = cs_base64_decode(reinterpret_cast<const unsigned char *>(server_response.c_str()),
                        server_response.size(),
                        reinterpret_cast<char *>(pIn),
                        NULL);

                    cbIn = what_is_this;
                    cbOut = BYTES_MAX_MESSAGE;

                    SecBuffer   InSecBuff;

                    OutDesc_.ulVersion = 0;
                    OutDesc_.cBuffers = 1;
                    OutDesc_.pBuffers = &OutSecBuff;

                    OutSecBuff.cbBuffer = *pcbOut;
                    OutSecBuff.BufferType = SECBUFFER_TOKEN;
                    OutSecBuff.pvBuffer = pOut;

                    ServerTokenDesc_.ulVersion = 0;
                    ServerTokenDesc_.cBuffers = 1;
                    ServerTokenDesc_.pBuffers = &InSecBuff;

                    InSecBuff.cbBuffer = cbIn;
                    InSecBuff.BufferType = SECBUFFER_TOKEN;
                    InSecBuff.pvBuffer = pIn;


                    ULONG ContextAttributes = 0;
                    SECURITY_STATUS  status = InitializeSecurityContext(
                        &hCred_,
                        &hContext_,
                        TARGET_INIT_SECURITY_CONTEXT,
                        CLIENT_SECURITY_REQUIREMENTS,
                        0,
                        SECURITY_NATIVE_DREP,
                        &ServerTokenDesc_,
                        0,
                        &hContext_,
                        &OutDesc_,
                        &ContextAttributes,
                        NULL);

                    *pcbOut = OutSecBuff.cbBuffer;
                    done = !((SEC_I_CONTINUE_NEEDED == status) ||
                        (SEC_I_COMPLETE_AND_CONTINUE == status));        

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "InitializeSecurityContext failed");

        

                    std::string output;
                    output.resize(cbOut * 2);

                    cs_base64_encode(pOut, cbOut, &output[0]);
                    output.erase(output.find_first_of('\0'));  // remove the string

        
                    return output;
                }

            private:
                CredHandle      hCred_;
                CtxtHandle      hContext_;
                SecBufferDesc   ServerTokenDesc_;
                SecBufferDesc   OutDesc_;
            };

            class TCPServer
            {
            public:
                void start()
                {
                    // STAT LISTENING AND READ
                    //
                    using boost::asio::ip::tcp;
                    tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), 32111));
                    tcp::socket sock(io_context);
                    a.accept(sock);        

                    char data[ASIO_BUFFER_SIZE];
                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    size_t length;

                    boost::system::error_code error;
                    length = sock.read_some(boost::asio::buffer(data), error);

                    if (error == boost::asio::error::eof)
                        return; // Connection closed cleanly by peer.

                    std::string client_token(data, length);
                    auto first_response = ntlm_server_.first_call(client_token);

                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    first_response.copy(data, first_response.size());
                    boost::asio::write(sock, boost::asio::buffer(data, first_response.size()));

                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    length = sock.read_some(boost::asio::buffer(data), error);
                    if (error == boost::asio::error::eof)
                        return; // Connection closed cleanly by peer.

                    client_token.assign(data, length);
                    ntlm_server_.second_call(client_token);
                }

            private:
                NTLMServer ntlm_server_;
                boost::asio::io_service io_context;
            };

            class TCPClient
            {
            public:
                void start()
                {   
                    // Connect
                    using boost::asio::ip::tcp;        
                    tcp::resolver resolver(io_context);
                    tcp::socket s(io_context);
                    s.connect( boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.10.92"), 32111));        

                    // Generate client token
                    const std::string msg = ntlm_client_.first_call();

                    char request[ASIO_BUFFER_SIZE];
                    std::memset(request, 0, ASIO_BUFFER_SIZE);
                    msg.copy(request, ASIO_BUFFER_SIZE);
                    size_t reply_length;

                    boost::asio::write(s, boost::asio::buffer(request, msg.size())); 

                    char reply[ASIO_BUFFER_SIZE];
                    reply_length = boost::asio::read(s, boost::asio::buffer(reply, 256));
                    std::string first_server_response(reply, reply_length);

                    auto second_msg = ntlm_client_.second_call(first_server_response);
                    std::memset(request, 0, ASIO_BUFFER_SIZE);
                    second_msg.copy(request, second_msg.size());

                    boost::asio::write(s, boost::asio::buffer(request, second_msg.size()));

                    std::this_thread::sleep_for(std::chrono::seconds(3));
                }
            private:
                NTLMClient ntlm_client_;
                boost::asio::io_service io_context;    
            };

            int main(int argc, char** argv)
            {
                if (argv[1][0] == 's')
                {
                    std::cout << "SERVER" << std::endl;
                    TCPServer server;
                    server.start();
                }

                if (argv[1][0] == 'c')
                {
                    std::cout << "CLIENT" << std::endl;
                    TCPClient client;
                    client.start();
                }   
    
                return EXIT_SUCCESS;    
            }



            // UTILITY

            #define BASE64_ENCODE_BODY                                                \
              static const char *b64 =                                                \
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
              int i, j, a, b, c;                                                      \
                                                                                     \
              for (i = j = 0; i < src_len; i += 3) {                                  \
                a = src[i];                                                          \
                b = i + 1 >= src_len ? 0 : src[i + 1];                                \
                c = i + 2 >= src_len ? 0 : src[i + 2];                                \
                                                                                     \
                BASE64_OUT(b64[a >> 2]);                                              \
                BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]);                           \
                if (i + 1 < src_len) {                                                \
                  BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]);                          \
                    }                                                                    \
                if (i + 2 < src_len) {                                                \
                  BASE64_OUT(b64[c & 63]);                                            \
                    }                                                                    \
                }                                                                      \
                                                                                     \
                                                                                       while (j % 4 != 0) {                                                    \
                BASE64_OUT('=');                                                      \
                                                                                         }                                                                      \
              BASE64_FLUSH()

            #define BASE64_OUT(ch) \
              do {                 \
                dst[j++] = (ch);   \
                } while (0)

            #define BASE64_FLUSH() \
              do {                 \
                dst[j++] = '\0';   \
                } while (0)

            void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
                BASE64_ENCODE_BODY;
            }

            const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"
            "0123456789+/";

            bool is_base64(unsigned char c) {
                return (std::isalnum(c) || (c == '+') || (c == '/'));
            }

            std::string base64_decode(std::string const& encoded_string)
            {
                int in_len = encoded_string.size();
                int i = 0;
                int j = 0;
                int in_ = 0;
                unsigned char char_array_4[4], char_array_3[3];
                std::string ret;

                while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
                    char_array_4[i++] = encoded_string[in_]; in_++;
                    if (i == 4) {
                        for (i = 0; i < 4; i++)
                            char_array_4[i] = base64_chars.find(char_array_4[i]);

                        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                        for (i = 0; (i < 3); i++)
                            ret += char_array_3[i];
                        i = 0;
                    }
                }

                if (i) {
                    for (j = i; j < 4; j++)
                        char_array_4[j] = 0;

                    for (j = 0; j < 4; j++)
                        char_array_4[j] = base64_chars.find(char_array_4[j]);

                    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
                }

                return ret;
            }

            std::string base64_encode(char const* bytes_to_encode, unsigned int in_len)
            {
                std::string ret;
                int i = 0;
                int j = 0;
                unsigned char char_array_3[3];
                unsigned char char_array_4[4];

                while (in_len--) {
                    char_array_3[i++] = *(bytes_to_encode++);
                    if (i == 3) {
                        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                        char_array_4[3] = char_array_3[2] & 0x3f;

                        for (i = 0; (i < 4); i++)
                            ret += base64_chars[char_array_4[i]];
                        i = 0;
                    }
                }

                if (i)
                {
                    for (j = i; j < 3; j++)
                        char_array_3[j] = '\0';

                    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                    char_array_4[3] = char_array_3[2] & 0x3f;

                    for (j = 0; (j < i + 1); j++)
                        ret += base64_chars[char_array_4[j]];

                    while ((i++ < 3))
                        ret += '=';

                }

                return ret;
            }


            static unsigned char from_b64(unsigned char ch) {
    
                static const unsigned char tab[128] = {
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  0 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  8 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  16 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  24 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  32 */
                    255, 255, 255, 62,
                    255, 255, 255, 63, /*  40 */
                    52, 53, 54, 55,
                    56, 57, 58, 59, /*  48 */
                    60, 61, 255, 255,
                    255, 200, 255, 255, /*  56   '=' is 200, on index 61 */
                    255, 0, 1, 2,
                    3, 4, 5, 6, /*  64 */
                    7, 8, 9, 10,
                    11, 12, 13, 14, /*  72 */
                    15, 16, 17, 18,
                    19, 20, 21, 22, /*  80 */
                    23, 24, 25, 255,
                    255, 255, 255, 255, /*  88 */
                    255, 26, 27, 28,
                    29, 30, 31, 32, /*  96 */
                    33, 34, 35, 36,
                    37, 38, 39, 40, /*  104 */
                    41, 42, 43, 44,
                    45, 46, 47, 48, /*  112 */
                    49, 50, 51, 255,
                    255, 255, 255, 255, /*  120 */
                };
                return tab[ch & 127];
            }


            int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
                unsigned char a, b, c, d;
                int orig_len = len;
                char *orig_dst = dst;
                while (len >= 4 && (a = from_b64(s[0])) != 255 &&
                    (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
                    (d = from_b64(s[3])) != 255) {
                    s += 4;
                    len -= 4;
                    if (a == 200 || b == 200) break; /* '=' can't be there */
                    *dst++ = a << 2 | b >> 4;
                    if (c == 200) break;
                    *dst++ = b << 4 | c >> 2;
                    if (d == 200) break;
                    *dst++ = c << 6 | d;
                }
                *dst = 0;
                if (dec_len != NULL) *dec_len = (dst - orig_dst);
                return orig_len - len;
            }


NTLM AcceptSecurityContext fails on remote machine, but works locally

$
0
0
I am trying to implement NTLM authentication in C++ using Windows API 

    InitializeSecurityContext
    AcquireCredentialsHandle
    AcceptSecurityContext

I implemented a server and a client which exchange the token generated using these functions. Everything works fine when I run server and client on the same machine, ... BUT as soon as I run the apps in 2 different machines ON THE SAME domain it does not work anymore.

To be precise the server call of <code>AcceptSecurityContext</code> fails with error <code>SEC_E_INVALID_TOKEN</code>.

Do you know what am I doing wrong?

Part of this code is taken from a WebServer. If I use INTERNET EXPLORER as client to connect from a remote machine works fin.

Is there anything I should check like Firewall or Networks security which prevents NTLM across 2 machines to work properly?

I am using <code>boost::asio</code> to exchange the tokens through the networks

Below The full listing. 

Once build is finished use command line 's' to start the server and 'c' to stat the client




            #pragma warning( disable: 4996 )

            #include <boost/asio.hpp>
            #include <boost/assert.hpp>
            #include <thread>

            #include <Windows.h>

            #define SECURITY_WIN32
            #include <Security.h>
            #include <cassert>
            #include <iostream>

            #define TARGET_INIT_SECURITY_CONTEXT "TEST/192.168.10.92"

            #define BYTES_MAX_MESSAGE            12000
            #define ASIO_BUFFER_SIZE             1024

            #define CLIENT_SECURITY_CONTEXT         "NTLM"
            #define CLIENT_SECURITY_REQUIREMENTS    ISC_REQ_CONNECTION

            #define SERVER_SECURITY_CONTEXT         "NTLM"
            #define SERVER_SECURITY_REQUIREMENETS   ASC_REQ_CONNECTION


            void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
            int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);

            std::string base64_decode(std::string const& encoded_string);
            std::string base64_encode(char const* bytes_to_encode, unsigned int in_len);


            class NTLMServer
            {
            public:
                std::string first_call(std::string clientToken_string)
                {
                    SECURITY_STATUS status = ::AcquireCredentialsHandle(NULL,
                        SERVER_SECURITY_CONTEXT,
                        SECPKG_CRED_INBOUND,            
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &serverCredentials_,
                        NULL);

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");        

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    SecBuffer serverOutBuffer_;
                    SecBufferDesc serverToken_;

                    serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                    serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                    serverOutBuffer_.pvBuffer = pOut;        

                    serverToken_.cBuffers = 1;
                    serverToken_.pBuffers = &serverOutBuffer_;
                    serverToken_.ulVersion = SECBUFFER_VERSION;

                    std::string out;        

                    SecBufferDesc clientToken;
                    SecBuffer clientOutBuffer;

                    {
                        std::string strToken = base64_decode(clientToken_string);            

                        BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                        std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                        strToken.copy(reinterpret_cast<char*>(pOut), strToken.size());

                        clientToken.cBuffers = 1;
                        clientToken.pBuffers = &clientOutBuffer;
                        clientToken.ulVersion = SECBUFFER_VERSION;

                        clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                        clientOutBuffer.cbBuffer = strToken.size();
                        clientOutBuffer.pvBuffer = pOut;

                        ULONG ContextAttributes = 0;

                        SECURITY_STATUS  status = AcceptSecurityContext(
                            &serverCredentials_,
                            NULL,
                            &clientToken,
                            SERVER_SECURITY_REQUIREMENETS,
                            SECURITY_NATIVE_DREP,
                            &hContext_,
                            &serverToken_,
                            &ContextAttributes,
                            NULL);

            
                        BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_OK, "AcceptSecurityContext failed");
            
                        int bufferSize = static_cast< int >(serverOutBuffer_.cbBuffer);
                        out = base64_encode(reinterpret_cast< const char *> (serverToken_.pBuffers->pvBuffer), bufferSize);
                    }

                    return out;
                }

                void second_call(const std::string& clientToken_string)
                {
                    SecBufferDesc clientToken;
                    SecBuffer clientOutBuffer;
        
                    std::string strToken = base64_decode(clientToken_string);        

                    BYTE       *pIn = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                    strToken.copy(reinterpret_cast<char*>(pIn), strToken.size());

                    clientToken.cBuffers = 1;
                    clientToken.pBuffers = &clientOutBuffer;
                    clientToken.ulVersion = SECBUFFER_VERSION;

                    clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                    clientOutBuffer.cbBuffer = strToken.size();
                    clientOutBuffer.pvBuffer = pIn;

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    SecBuffer serverOutBuffer_;
                    SecBufferDesc serverToken_;

                    serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                    serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                    serverOutBuffer_.pvBuffer = pOut;         

                    serverToken_.cBuffers = 1;
                    serverToken_.pBuffers = &serverOutBuffer_;
                    serverToken_.ulVersion = SECBUFFER_VERSION;

                    ULONG ContextAttributes = 0;

                    SECURITY_STATUS  status = AcceptSecurityContext(
                        &serverCredentials_,
                        &hContext_,
                        &clientToken,
                        SERVER_SECURITY_REQUIREMENETS,
                        SECURITY_NATIVE_DREP,
                        &hContext_,
                        &serverToken_,
                        &ContextAttributes,
                        NULL);
            
                    BOOST_ASSERT_MSG(status != SEC_E_INVALID_TOKEN, "Invalid Token!?!?!?");
                    BOOST_ASSERT_MSG(status == SEC_E_OK, "NOT OK?!?!?" );
                }

                CredHandle      serverCredentials_;
                CtxtHandle      hContext_;
            };

            class NTLMClient
            {
            public:
                std::string first_call()
                {
                    ULONG ContextAttributes = 0;
                    SECURITY_STATUS  status = AcquireCredentialsHandle(
                        NULL,
                        CLIENT_SECURITY_CONTEXT,
                        SECPKG_CRED_OUTBOUND,            
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &hCred_,
                        NULL);

        

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");

                    SecBuffer   OutSecBuff;

                    BYTE       *pIn = NULL;

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    BOOL   fDone = FALSE;
                    BOOL       *pfDone = &fDone;

                    DWORD       cbOut = BYTES_MAX_MESSAGE;
                    DWORD      *pcbOut = &cbOut;

                    OutDesc_.ulVersion = 0;
                    OutDesc_.cBuffers = 1;
                    OutDesc_.pBuffers = &OutSecBuff;

                    OutSecBuff.cbBuffer = *pcbOut;
                    OutSecBuff.BufferType = SECBUFFER_TOKEN;
                    OutSecBuff.pvBuffer = pOut;

                    status = InitializeSecurityContext(
                        &hCred_,
                        NULL,
                        TARGET_INIT_SECURITY_CONTEXT,
                        CLIENT_SECURITY_REQUIREMENTS,
                        0,
                        SECURITY_NATIVE_DREP,
                        NULL,
                        0,
                        &hContext_,
                        &OutDesc_,
                        &ContextAttributes,
                        NULL);

        

                    BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED, "InitializeSecurityContext failed");

                    *pcbOut = OutSecBuff.cbBuffer;
                    *pfDone = !((SEC_I_CONTINUE_NEEDED == status) ||
                        (SEC_I_COMPLETE_AND_CONTINUE == status));

        

                    std::string output;
                    output.resize(cbOut * 2);

                    cs_base64_encode(pOut, cbOut, &output[0]);
                    output.erase(output.find_first_of('\0'));  // remove the string
        
                    return output;
                }

                std::string second_call(const std::string& server_response)
                {        
                    SecBuffer   OutSecBuff;

                    BYTE       *pIn;
                    BYTE       *pOut;

                    DWORD       cbOut = 0;
                    DWORD      *pcbOut = &cbOut;

                    BOOL        done;
                    DWORD       cbIn;

                    pIn = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    int what_is_this = cs_base64_decode(reinterpret_cast<const unsigned char *>(server_response.c_str()),
                        server_response.size(),
                        reinterpret_cast<char *>(pIn),
                        NULL);

                    cbIn = what_is_this;
                    cbOut = BYTES_MAX_MESSAGE;

                    SecBuffer   InSecBuff;

                    OutDesc_.ulVersion = 0;
                    OutDesc_.cBuffers = 1;
                    OutDesc_.pBuffers = &OutSecBuff;

                    OutSecBuff.cbBuffer = *pcbOut;
                    OutSecBuff.BufferType = SECBUFFER_TOKEN;
                    OutSecBuff.pvBuffer = pOut;

                    ServerTokenDesc_.ulVersion = 0;
                    ServerTokenDesc_.cBuffers = 1;
                    ServerTokenDesc_.pBuffers = &InSecBuff;

                    InSecBuff.cbBuffer = cbIn;
                    InSecBuff.BufferType = SECBUFFER_TOKEN;
                    InSecBuff.pvBuffer = pIn;


                    ULONG ContextAttributes = 0;
                    SECURITY_STATUS  status = InitializeSecurityContext(
                        &hCred_,
                        &hContext_,
                        TARGET_INIT_SECURITY_CONTEXT,
                        CLIENT_SECURITY_REQUIREMENTS,
                        0,
                        SECURITY_NATIVE_DREP,
                        &ServerTokenDesc_,
                        0,
                        &hContext_,
                        &OutDesc_,
                        &ContextAttributes,
                        NULL);

                    *pcbOut = OutSecBuff.cbBuffer;
                    done = !((SEC_I_CONTINUE_NEEDED == status) ||
                        (SEC_I_COMPLETE_AND_CONTINUE == status));        

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "InitializeSecurityContext failed");

        

                    std::string output;
                    output.resize(cbOut * 2);

                    cs_base64_encode(pOut, cbOut, &output[0]);
                    output.erase(output.find_first_of('\0'));  // remove the string

        
                    return output;
                }

            private:
                CredHandle      hCred_;
                CtxtHandle      hContext_;
                SecBufferDesc   ServerTokenDesc_;
                SecBufferDesc   OutDesc_;
            };

            class TCPServer
            {
            public:
                void start()
                {
                    // STAT LISTENING AND READ
                    //
                    using boost::asio::ip::tcp;
                    tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), 32111));
                    tcp::socket sock(io_context);
                    a.accept(sock);        

                    char data[ASIO_BUFFER_SIZE];
                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    size_t length;

                    boost::system::error_code error;
                    length = sock.read_some(boost::asio::buffer(data), error);

                    if (error == boost::asio::error::eof)
                        return; // Connection closed cleanly by peer.

                    std::string client_token(data, length);
                    auto first_response = ntlm_server_.first_call(client_token);

                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    first_response.copy(data, first_response.size());
                    boost::asio::write(sock, boost::asio::buffer(data, first_response.size()));

                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    length = sock.read_some(boost::asio::buffer(data), error);
                    if (error == boost::asio::error::eof)
                        return; // Connection closed cleanly by peer.

                    client_token.assign(data, length);
                    ntlm_server_.second_call(client_token);
                }

            private:
                NTLMServer ntlm_server_;
                boost::asio::io_service io_context;
            };

            class TCPClient
            {
            public:
                void start()
                {   
                    // Connect
                    using boost::asio::ip::tcp;        
                    tcp::resolver resolver(io_context);
                    tcp::socket s(io_context);
                    s.connect( boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.10.92"), 32111));        

                    // Generate client token
                    const std::string msg = ntlm_client_.first_call();

                    char request[ASIO_BUFFER_SIZE];
                    std::memset(request, 0, ASIO_BUFFER_SIZE);
                    msg.copy(request, ASIO_BUFFER_SIZE);
                    size_t reply_length;

                    boost::asio::write(s, boost::asio::buffer(request, msg.size())); 

                    char reply[ASIO_BUFFER_SIZE];
                    reply_length = boost::asio::read(s, boost::asio::buffer(reply, 256));
                    std::string first_server_response(reply, reply_length);

                    auto second_msg = ntlm_client_.second_call(first_server_response);
                    std::memset(request, 0, ASIO_BUFFER_SIZE);
                    second_msg.copy(request, second_msg.size());

                    boost::asio::write(s, boost::asio::buffer(request, second_msg.size()));

                    std::this_thread::sleep_for(std::chrono::seconds(3));
                }
            private:
                NTLMClient ntlm_client_;
                boost::asio::io_service io_context;    
            };

            int main(int argc, char** argv)
            {
                if (argv[1][0] == 's')
                {
                    std::cout << "SERVER" << std::endl;
                    TCPServer server;
                    server.start();
                }

                if (argv[1][0] == 'c')
                {
                    std::cout << "CLIENT" << std::endl;
                    TCPClient client;
                    client.start();
                }   
    
                return EXIT_SUCCESS;    
            }



            // UTILITY

            #define BASE64_ENCODE_BODY                                                \
              static const char *b64 =                                                \
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
              int i, j, a, b, c;                                                      \
                                                                                     \
              for (i = j = 0; i < src_len; i += 3) {                                  \
                a = src[i];                                                          \
                b = i + 1 >= src_len ? 0 : src[i + 1];                                \
                c = i + 2 >= src_len ? 0 : src[i + 2];                                \
                                                                                     \
                BASE64_OUT(b64[a >> 2]);                                              \
                BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]);                           \
                if (i + 1 < src_len) {                                                \
                  BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]);                          \
                    }                                                                    \
                if (i + 2 < src_len) {                                                \
                  BASE64_OUT(b64[c & 63]);                                            \
                    }                                                                    \
                }                                                                      \
                                                                                     \
                                                                                       while (j % 4 != 0) {                                                    \
                BASE64_OUT('=');                                                      \
                                                                                         }                                                                      \
              BASE64_FLUSH()

            #define BASE64_OUT(ch) \
              do {                 \
                dst[j++] = (ch);   \
                } while (0)

            #define BASE64_FLUSH() \
              do {                 \
                dst[j++] = '\0';   \
                } while (0)

            void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
                BASE64_ENCODE_BODY;
            }

            const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"
            "0123456789+/";

            bool is_base64(unsigned char c) {
                return (std::isalnum(c) || (c == '+') || (c == '/'));
            }

            std::string base64_decode(std::string const& encoded_string)
            {
                int in_len = encoded_string.size();
                int i = 0;
                int j = 0;
                int in_ = 0;
                unsigned char char_array_4[4], char_array_3[3];
                std::string ret;

                while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
                    char_array_4[i++] = encoded_string[in_]; in_++;
                    if (i == 4) {
                        for (i = 0; i < 4; i++)
                            char_array_4[i] = base64_chars.find(char_array_4[i]);

                        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                        for (i = 0; (i < 3); i++)
                            ret += char_array_3[i];
                        i = 0;
                    }
                }

                if (i) {
                    for (j = i; j < 4; j++)
                        char_array_4[j] = 0;

                    for (j = 0; j < 4; j++)
                        char_array_4[j] = base64_chars.find(char_array_4[j]);

                    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
                }

                return ret;
            }

            std::string base64_encode(char const* bytes_to_encode, unsigned int in_len)
            {
                std::string ret;
                int i = 0;
                int j = 0;
                unsigned char char_array_3[3];
                unsigned char char_array_4[4];

                while (in_len--) {
                    char_array_3[i++] = *(bytes_to_encode++);
                    if (i == 3) {
                        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                        char_array_4[3] = char_array_3[2] & 0x3f;

                        for (i = 0; (i < 4); i++)
                            ret += base64_chars[char_array_4[i]];
                        i = 0;
                    }
                }

                if (i)
                {
                    for (j = i; j < 3; j++)
                        char_array_3[j] = '\0';

                    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                    char_array_4[3] = char_array_3[2] & 0x3f;

                    for (j = 0; (j < i + 1); j++)
                        ret += base64_chars[char_array_4[j]];

                    while ((i++ < 3))
                        ret += '=';

                }

                return ret;
            }


            static unsigned char from_b64(unsigned char ch) {
    
                static const unsigned char tab[128] = {
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  0 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  8 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  16 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  24 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  32 */
                    255, 255, 255, 62,
                    255, 255, 255, 63, /*  40 */
                    52, 53, 54, 55,
                    56, 57, 58, 59, /*  48 */
                    60, 61, 255, 255,
                    255, 200, 255, 255, /*  56   '=' is 200, on index 61 */
                    255, 0, 1, 2,
                    3, 4, 5, 6, /*  64 */
                    7, 8, 9, 10,
                    11, 12, 13, 14, /*  72 */
                    15, 16, 17, 18,
                    19, 20, 21, 22, /*  80 */
                    23, 24, 25, 255,
                    255, 255, 255, 255, /*  88 */
                    255, 26, 27, 28,
                    29, 30, 31, 32, /*  96 */
                    33, 34, 35, 36,
                    37, 38, 39, 40, /*  104 */
                    41, 42, 43, 44,
                    45, 46, 47, 48, /*  112 */
                    49, 50, 51, 255,
                    255, 255, 255, 255, /*  120 */
                };
                return tab[ch & 127];
            }


            int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
                unsigned char a, b, c, d;
                int orig_len = len;
                char *orig_dst = dst;
                while (len >= 4 && (a = from_b64(s[0])) != 255 &&
                    (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
                    (d = from_b64(s[3])) != 255) {
                    s += 4;
                    len -= 4;
                    if (a == 200 || b == 200) break; /* '=' can't be there */
                    *dst++ = a << 2 | b >> 4;
                    if (c == 200) break;
                    *dst++ = b << 4 | c >> 2;
                    if (d == 200) break;
                    *dst++ = c << 6 | d;
                }
                *dst = 0;
                if (dec_len != NULL) *dec_len = (dst - orig_dst);
                return orig_len - len;
            }


NTLM Authentication fails with INVALID TOKEN error

$
0
0

I am trying to implement NTLM authentication in C++ using Windows API 

    InitializeSecurityContext
    AcquireCredentialsHandle
    AcceptSecurityContext

I implemented a server and a client which exchange the token generated using these functions. Everything works fine when I run server and client on the same machine, ... BUT as soon as I run the apps in 2 different machines ON THE SAME domain it does not work anymore.

To be precise the server call of AcceptSecurityContext fails with errorSEC_E_INVALID_TOKEN.

Do you know what am I doing wrong?

Part of this code is taken from a WebServer. If I use INTERNET EXPLORER as client to connect from a remote machine works fin.

Is there anything I should check like Firewall or Networks security which prevents NTLM across 2 machines to work properly?

I am using <code>boost::asio</code> to exchange the tokens through the networks

Below The full listing. 

Once build is finished use command line 's' to start the server and 'c' to stat the client
            #pragma warning( disable: 4996 )

            #include <boost/asio.hpp>
            #include <boost/assert.hpp>
            #include <thread>

            #include <Windows.h>

            #define SECURITY_WIN32
            #include <Security.h>
            #include <cassert>
            #include <iostream>

            #define TARGET_INIT_SECURITY_CONTEXT "TEST/192.168.10.92"

            #define BYTES_MAX_MESSAGE            12000
            #define ASIO_BUFFER_SIZE             1024

            #define CLIENT_SECURITY_CONTEXT         "NTLM"
            #define CLIENT_SECURITY_REQUIREMENTS    ISC_REQ_CONNECTION

            #define SERVER_SECURITY_CONTEXT         "NTLM"
            #define SERVER_SECURITY_REQUIREMENETS   ASC_REQ_CONNECTION


            void cs_base64_encode(const unsigned char *src, int src_len, char *dst);
            int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len);

            std::string base64_decode(std::string const& encoded_string);
            std::string base64_encode(char const* bytes_to_encode, unsigned int in_len);


            class NTLMServer
            {
            public:
                std::string first_call(std::string clientToken_string)
                {
                    SECURITY_STATUS status = ::AcquireCredentialsHandle(NULL,
                        SERVER_SECURITY_CONTEXT,
                        SECPKG_CRED_INBOUND,            
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &serverCredentials_,
                        NULL);

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");        

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    SecBuffer serverOutBuffer_;
                    SecBufferDesc serverToken_;

                    serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                    serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                    serverOutBuffer_.pvBuffer = pOut;        

                    serverToken_.cBuffers = 1;
                    serverToken_.pBuffers = &serverOutBuffer_;
                    serverToken_.ulVersion = SECBUFFER_VERSION;

                    std::string out;        

                    SecBufferDesc clientToken;
                    SecBuffer clientOutBuffer;

                    {
                        std::string strToken = base64_decode(clientToken_string);            

                        BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                        std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                        strToken.copy(reinterpret_cast<char*>(pOut), strToken.size());

                        clientToken.cBuffers = 1;
                        clientToken.pBuffers = &clientOutBuffer;
                        clientToken.ulVersion = SECBUFFER_VERSION;

                        clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                        clientOutBuffer.cbBuffer = strToken.size();
                        clientOutBuffer.pvBuffer = pOut;

                        ULONG ContextAttributes = 0;

                        SECURITY_STATUS  status = AcceptSecurityContext(
                            &serverCredentials_,
                            NULL,&clientToken,
                            SERVER_SECURITY_REQUIREMENETS,
                            SECURITY_NATIVE_DREP,&hContext_,&serverToken_,&ContextAttributes,
                            NULL);


                        BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_OK, "AcceptSecurityContext failed");

                        int bufferSize = static_cast< int >(serverOutBuffer_.cbBuffer);
                        out = base64_encode(reinterpret_cast< const char *> (serverToken_.pBuffers->pvBuffer), bufferSize);
                    }

                    return out;
                }

                void second_call(const std::string& clientToken_string)
                {
                    SecBufferDesc clientToken;
                    SecBuffer clientOutBuffer;

                    std::string strToken = base64_decode(clientToken_string);        

                    BYTE       *pIn = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);
                    strToken.copy(reinterpret_cast<char*>(pIn), strToken.size());

                    clientToken.cBuffers = 1;
                    clientToken.pBuffers = &clientOutBuffer;
                    clientToken.ulVersion = SECBUFFER_VERSION;

                    clientOutBuffer.BufferType = SECBUFFER_TOKEN;
                    clientOutBuffer.cbBuffer = strToken.size();
                    clientOutBuffer.pvBuffer = pIn;

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    SecBuffer serverOutBuffer_;
                    SecBufferDesc serverToken_;

                    serverOutBuffer_.BufferType = SECBUFFER_TOKEN;
                    serverOutBuffer_.cbBuffer = BYTES_MAX_MESSAGE;
                    serverOutBuffer_.pvBuffer = pOut;         

                    serverToken_.cBuffers = 1;
                    serverToken_.pBuffers = &serverOutBuffer_;
                    serverToken_.ulVersion = SECBUFFER_VERSION;

                    ULONG ContextAttributes = 0;

                    SECURITY_STATUS  status = AcceptSecurityContext(
                        &serverCredentials_,&hContext_,&clientToken,
                        SERVER_SECURITY_REQUIREMENETS,
                        SECURITY_NATIVE_DREP,&hContext_,&serverToken_,&ContextAttributes,
                        NULL);

                    BOOST_ASSERT_MSG(status != SEC_E_INVALID_TOKEN, "Invalid Token!?!?!?");
                    BOOST_ASSERT_MSG(status == SEC_E_OK, "NOT OK?!?!?" );
                }

                CredHandle      serverCredentials_;
                CtxtHandle      hContext_;
            };

            class NTLMClient
            {
            public:
                std::string first_call()
                {
                    ULONG ContextAttributes = 0;
                    SECURITY_STATUS  status = AcquireCredentialsHandle(
                        NULL,
                        CLIENT_SECURITY_CONTEXT,
                        SECPKG_CRED_OUTBOUND,            
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        &hCred_,
                        NULL);



                    BOOST_ASSERT_MSG(status == SEC_E_OK, "AcquireCredentialsHandle failed");

                    SecBuffer   OutSecBuff;

                    BYTE       *pIn = NULL;

                    BYTE       *pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    BOOL	   fDone = FALSE;
                    BOOL       *pfDone = &fDone;

                    DWORD       cbOut = BYTES_MAX_MESSAGE;
                    DWORD      *pcbOut = &cbOut;

                    OutDesc_.ulVersion = 0;
                    OutDesc_.cBuffers = 1;
                    OutDesc_.pBuffers = &OutSecBuff;

                    OutSecBuff.cbBuffer = *pcbOut;
                    OutSecBuff.BufferType = SECBUFFER_TOKEN;
                    OutSecBuff.pvBuffer = pOut;

                    status = InitializeSecurityContext(
                        &hCred_,
                        NULL,
                        TARGET_INIT_SECURITY_CONTEXT,
                        CLIENT_SECURITY_REQUIREMENTS,
                        0,
                        SECURITY_NATIVE_DREP,
                        NULL,
                        0,&hContext_,&OutDesc_,&ContextAttributes,
                        NULL);



                    BOOST_ASSERT_MSG(status == SEC_I_CONTINUE_NEEDED, "InitializeSecurityContext failed");

                    *pcbOut = OutSecBuff.cbBuffer;
                    *pfDone = !((SEC_I_CONTINUE_NEEDED == status) ||
                        (SEC_I_COMPLETE_AND_CONTINUE == status));



                    std::string output;
                    output.resize(cbOut * 2);

                    cs_base64_encode(pOut, cbOut, &output[0]);
                    output.erase(output.find_first_of('\0'));  // remove the string

                    return output;
                }

                std::string second_call(const std::string& server_response)
                {        
                    SecBuffer   OutSecBuff;

                    BYTE       *pIn;
                    BYTE       *pOut;

                    DWORD       cbOut = 0;
                    DWORD      *pcbOut = &cbOut;

                    BOOL        done;
                    DWORD       cbIn;

                    pIn = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pIn, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    pOut = new BYTE[BYTES_MAX_MESSAGE];
                    std::memset(pOut, 0, sizeof(BYTE) * BYTES_MAX_MESSAGE);

                    int what_is_this = cs_base64_decode(reinterpret_cast<const unsigned char *>(server_response.c_str()),
                        server_response.size(),
                        reinterpret_cast<char *>(pIn),
                        NULL);

                    cbIn = what_is_this;
                    cbOut = BYTES_MAX_MESSAGE;

                    SecBuffer   InSecBuff;

                    OutDesc_.ulVersion = 0;
                    OutDesc_.cBuffers = 1;
                    OutDesc_.pBuffers = &OutSecBuff;

                    OutSecBuff.cbBuffer = *pcbOut;
                    OutSecBuff.BufferType = SECBUFFER_TOKEN;
                    OutSecBuff.pvBuffer = pOut;

                    ServerTokenDesc_.ulVersion = 0;
                    ServerTokenDesc_.cBuffers = 1;
                    ServerTokenDesc_.pBuffers = &InSecBuff;

                    InSecBuff.cbBuffer = cbIn;
                    InSecBuff.BufferType = SECBUFFER_TOKEN;
                    InSecBuff.pvBuffer = pIn;


                    ULONG ContextAttributes = 0;
                    SECURITY_STATUS  status = InitializeSecurityContext(
                     &hCred_,&hContext_,
                        TARGET_INIT_SECURITY_CONTEXT,
                        CLIENT_SECURITY_REQUIREMENTS,
                        0,
                        SECURITY_NATIVE_DREP,&ServerTokenDesc_,
                        0,&hContext_,&OutDesc_,&ContextAttributes,
                        NULL);

                    *pcbOut = OutSecBuff.cbBuffer;
                    done = !((SEC_I_CONTINUE_NEEDED == status) ||
                        (SEC_I_COMPLETE_AND_CONTINUE == status));        

                    BOOST_ASSERT_MSG(status == SEC_E_OK, "InitializeSecurityContext failed");



                    std::string output;
                    output.resize(cbOut * 2);

                    cs_base64_encode(pOut, cbOut, &output[0]);
                    output.erase(output.find_first_of('\0'));  // remove the string


                    return output;
                }

            private:
                CredHandle      hCred_;
                CtxtHandle      hContext_;
                SecBufferDesc   ServerTokenDesc_;
                SecBufferDesc   OutDesc_;
            };

            class TCPServer
            {
            public:
                void start()
                {
                    // STAT LISTENING AND READ
                    //
                    using boost::asio::ip::tcp;
                    tcp::acceptor a(io_context, tcp::endpoint(tcp::v4(), 32111));
                    tcp::socket sock(io_context);
                    a.accept(sock);        

                    char data[ASIO_BUFFER_SIZE];
                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    size_t length;

                    boost::system::error_code error;
                    length = sock.read_some(boost::asio::buffer(data), error);

                    if (error == boost::asio::error::eof)
                        return; // Connection closed cleanly by peer.

                    std::string client_token(data, length);
                    auto first_response = ntlm_server_.first_call(client_token);

                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    first_response.copy(data, first_response.size());
                    boost::asio::write(sock, boost::asio::buffer(data, first_response.size()));

                    std::memset(data, 0, ASIO_BUFFER_SIZE);
                    length = sock.read_some(boost::asio::buffer(data), error);
                    if (error == boost::asio::error::eof)
                        return; // Connection closed cleanly by peer.

                    client_token.assign(data, length);
                    ntlm_server_.second_call(client_token);
                }

            private:
                NTLMServer ntlm_server_;
                boost::asio::io_service io_context;
            };

            class TCPClient
            {
            public:
                void start()
                {   
                    // Connect
                    using boost::asio::ip::tcp;        
                    tcp::resolver resolver(io_context);
                    tcp::socket s(io_context);
                    s.connect( boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("192.168.10.92"), 32111));        

                    // Generate client token
                    const std::string msg = ntlm_client_.first_call();

                    char request[ASIO_BUFFER_SIZE];
                    std::memset(request, 0, ASIO_BUFFER_SIZE);
                    msg.copy(request, ASIO_BUFFER_SIZE);
                    size_t reply_length;

                    boost::asio::write(s, boost::asio::buffer(request, msg.size())); 

                    char reply[ASIO_BUFFER_SIZE];
                    reply_length = boost::asio::read(s, boost::asio::buffer(reply, 256));
                    std::string first_server_response(reply, reply_length);

                    auto second_msg = ntlm_client_.second_call(first_server_response);
                    std::memset(request, 0, ASIO_BUFFER_SIZE);
                    second_msg.copy(request, second_msg.size());

                    boost::asio::write(s, boost::asio::buffer(request, second_msg.size()));

                    std::this_thread::sleep_for(std::chrono::seconds(3));
                }
            private:
                NTLMClient ntlm_client_;
                boost::asio::io_service io_context;    
            };

            int main(int argc, char** argv)
            {
                if (argv[1][0] == 's')
                {
                    std::cout << "SERVER" << std::endl;
                    TCPServer server;
                    server.start();
                }

                if (argv[1][0] == 'c')
                {
                    std::cout << "CLIENT" << std::endl;
                    TCPClient client;
                    client.start();
                }   

                return EXIT_SUCCESS;    
            }



            // UTILITY

            #define BASE64_ENCODE_BODY                                                \
              static const char *b64 =                                                \
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \
              int i, j, a, b, c;                                                      \
                                                                                      \
              for (i = j = 0; i < src_len; i += 3) {                                  \
                a = src[i];                                                           \
                b = i + 1 >= src_len ? 0 : src[i + 1];                                \
                c = i + 2 >= src_len ? 0 : src[i + 2];                                \
                                                                                      \
                BASE64_OUT(b64[a >> 2]);                                              \
                BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]);                           \
                if (i + 1 < src_len) {                                                \
                  BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]);                          \
                    }                                                                     \
                if (i + 2 < src_len) {                                                \
                  BASE64_OUT(b64[c & 63]);                                            \
                    }                                                                     \
                }                                                                       \
                                                                                      \
                                                                                        while (j % 4 != 0) {                                                    \
                BASE64_OUT('=');                                                      \
                                                                                          }                                                                       \
              BASE64_FLUSH()

            #define BASE64_OUT(ch) \
              do {                 \
                dst[j++] = (ch);   \
                } while (0)

            #define BASE64_FLUSH() \
              do {                 \
                dst[j++] = '\0';   \
                } while (0)

            void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
                BASE64_ENCODE_BODY;
            }

            const std::string base64_chars =
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz""0123456789+/";

            bool is_base64(unsigned char c) {
                return (std::isalnum(c) || (c == '+') || (c == '/'));
            }

            std::string base64_decode(std::string const& encoded_string)
            {
                int in_len = encoded_string.size();
                int i = 0;
                int j = 0;
                int in_ = 0;
                unsigned char char_array_4[4], char_array_3[3];
                std::string ret;

                while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
                    char_array_4[i++] = encoded_string[in_]; in_++;
                    if (i == 4) {
                        for (i = 0; i < 4; i++)
                            char_array_4[i] = base64_chars.find(char_array_4[i]);

                        char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                        char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                        char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                        for (i = 0; (i < 3); i++)
                            ret += char_array_3[i];
                        i = 0;
                    }
                }

                if (i) {
                    for (j = i; j < 4; j++)
                        char_array_4[j] = 0;

                    for (j = 0; j < 4; j++)
                        char_array_4[j] = base64_chars.find(char_array_4[j]);

                    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
                    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
                    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

                    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
                }

                return ret;
            }

            std::string base64_encode(char const* bytes_to_encode, unsigned int in_len)
            {
                std::string ret;
                int i = 0;
                int j = 0;
                unsigned char char_array_3[3];
                unsigned char char_array_4[4];

                while (in_len--) {
                    char_array_3[i++] = *(bytes_to_encode++);
                    if (i == 3) {
                        char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                        char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                        char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                        char_array_4[3] = char_array_3[2] & 0x3f;

                        for (i = 0; (i < 4); i++)
                            ret += base64_chars[char_array_4[i]];
                        i = 0;
                    }
                }

                if (i)
                {
                    for (j = i; j < 3; j++)
                        char_array_3[j] = '\0';

                    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                    char_array_4[3] = char_array_3[2] & 0x3f;

                    for (j = 0; (j < i + 1); j++)
                        ret += base64_chars[char_array_4[j]];

                    while ((i++ < 3))
                        ret += '=';

                }

                return ret;
            }


            static unsigned char from_b64(unsigned char ch) {

                static const unsigned char tab[128] = {
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  0 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  8 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  16 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  24 */
                    255, 255, 255, 255,
                    255, 255, 255, 255, /*  32 */
                    255, 255, 255, 62,
                    255, 255, 255, 63, /*  40 */
                    52, 53, 54, 55,
                    56, 57, 58, 59, /*  48 */
                    60, 61, 255, 255,
                    255, 200, 255, 255, /*  56   '=' is 200, on index 61 */
                    255, 0, 1, 2,
                    3, 4, 5, 6, /*  64 */
                    7, 8, 9, 10,
                    11, 12, 13, 14, /*  72 */
                    15, 16, 17, 18,
                    19, 20, 21, 22, /*  80 */
                    23, 24, 25, 255,
                    255, 255, 255, 255, /*  88 */
                    255, 26, 27, 28,
                    29, 30, 31, 32, /*  96 */
                    33, 34, 35, 36,
                    37, 38, 39, 40, /*  104 */
                    41, 42, 43, 44,
                    45, 46, 47, 48, /*  112 */
                    49, 50, 51, 255,
                    255, 255, 255, 255, /*  120 */
                };
                return tab[ch & 127];
            }


            int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) {
                unsigned char a, b, c, d;
                int orig_len = len;
                char *orig_dst = dst;
                while (len >= 4 && (a = from_b64(s[0])) != 255 &&
                    (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 &&
                    (d = from_b64(s[3])) != 255) {
                    s += 4;
                    len -= 4;
                    if (a == 200 || b == 200) break; /* '=' can't be there */
                    *dst++ = a << 2 | b >> 4;
                    if (c == 200) break;
                    *dst++ = b << 4 | c >> 2;
                    if (d == 200) break;
                    *dst++ = c << 6 | d;
                }
                *dst = 0;
                if (dec_len != NULL) *dec_len = (dst - orig_dst);
                return orig_len - len;
            }




Scaling a bitmap in a static picture

$
0
0

For god sake

Surely there must be a SIMPLE way to get a bitmap (loaded from a file) to fit within a static picture control?

How??

This is the code I have that successfully puts the bitmap into the static control. But I can't find any way (that works for me) to scale the bitmap.

void CGregsLaserEngraverDlg::LoadBitmap()
{
    if (!m_strFilename.IsEmpty())
    {
        CBitmap bmp;
        HBITMAP hBitmap = (HBITMAP)::LoadImage(AfxGetInstanceHandle(), m_strFolder + "\\" + m_strFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_VGACOLOR);
        bmp.Attach(hBitmap);
        m_staticBMP.SetBitmap(bmp);

        BITMAP bitmap;
        bmp.GetBitmap(&bitmap);

        UpdateData(false);
    }
}


I have tried this sort of thing but it has not effect what so ever on the displayed bitmap:

		CDC *pDC = GetDC(), dc;
		CRect rect;
		CBitmap bmpScaled, *pBMPScaled = NULL;

		m_staticBMP.GetClientRect(rect);
		dc.CreateCompatibleDC(pDC);
		bmpScaled.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
		pBMPScaled = dc.SelectObject(&bmpScaled);
		dc.StretchBlt(0, 0, rect.Width(), rect.Height(), &dc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
		//dc.SelectObject(pob);
		//Bitmap_.SetBitmap((HBITMAP)scale_bitmap.Detach());
		ReleaseDC(pDC);


how to browse image in the center of dialog box in mfc vc++

Problems creating COM event handler

$
0
0

I have been able to successfully invoke functions in a COM interface.  But I continue to struggle with creating an event handler for the same COM object.

My code contains the following import statement:

#import "LogosCOM.tlb"

And this .tlb file was created from the .exe file which contains the COM object.  The import creates 2 files - logoscom.tli and logoscom.tlh - which provides the interface and the header file definitions, respectively.

In the .tlh file, I find the following:

struct __declspec(uuid("d80579b0-eb69-4217-a170-f0bec30b2672"))
ILogosApplicationEvents : IDispatch
{
   // Methods:
   HRESULT PanelOpened(IDispatch *Panel);
   HRESULT PanelActivated(IDispatch *Panel);
   HRESULT PanelChanged(IDispatch *Panel, IDispatch* Hint);
   HRESULT PanelClosed(IDispatch * Panel);
   HRESULT Exiting();
};

I want my program to handle the "PanelChanged" event.

I set things up in my C++ code based on this online documentation:
https://docs.microsoft.com/en-us/cpp/cpp/event-handling-in-native-cpp

I tried following the example, and got 95% of the way there, but ran into one small(?) error...  Here's the relevant code I created:

[event_receiver(native)]
class CEventReceiver
{
public:
    void OnLogosPanelChanged(IDispatch * Panel, IDispatch * Hint)
    {
        printf_s("OnLogosPanelChanged was called.\n");
    }

    void hookEvent(Logos4Lib::ILogosApplicationEvents *pEventSource)
    {
        __hook(&Logos4Lib::ILogosApplicationEvents::PanelChanged, pEventSource,&CEventReceiver::OnLogosPanelChanged);
    }

    void unhookEvent(Logos4Lib::ILogosApplicationEvents *pEventSource)
    {
        __unhook(&Logos4Lib::ILogosApplicationEvents::PanelChanged, pEventSource,&CEventReceiver::OnLogosPanelChanged);
    }
};

OnLogosPanelChanged() is the callback function.  The hookEvent() method tells the COM object to use this callback function to handle the specified event.

Then I put this code elsewhere in my program (where I set up the connection to the COM object):

    Logos4Lib::ILogosApplicationEvents eventSource;
    CEventReceiver eventReceiver;
    eventReceiver.hookEvent(&eventSource);

The IDE flags an error on the declaration of eventSource:  "error C2259: 'Logos4Lib::ILogosApplicationEvents': cannot instantiate abstract class".

I'm not sure why this is abstract, given its definition above.  When I try to compile, I get more error messages:

linklogos.cpp(39): warning C4467: usage of ATL attributes is deprecated

This relates to the line:

[event_receiver(native)]

linklogos.cpp(50): error C3723: 'Logos4Lib::ILogosApplicationEvents::PanelChanged':could not resolve event
logoscom.tli(113): note: see declaration of 'Logos4Lib::ILogosApplicationEvents::PanelChanged'
linklogos.cpp(50): note: The event handler is one of:
linklogos.cpp(50): note: could be 'void CEventReceiver::OnLogosPanelChanged(IDispatch *,IDispatch* )'
linklogos.cpp(50): note: There are no events:
logoscom.tli(113): note:     'HRESULT Logos4Lib::ILogosApplicationEvents::PanelChanged(IDispatch *,IDispatch* )':is not an event

This error relates to the line:

    __hook(&Logos4Lib::ILogosApplicationEvents::PanelChanged, pEventSource,&CEventReceiver::OnLogosPanelChanged);


linklogos.cpp(56): error C3723: 'Logos4Lib::ILogosApplicationEvents::PanelChanged':could not resolve event
logoscom.tli(113): note: see declaration of 'Logos4Lib::ILogosApplicationEvents::PanelChanged'
linklogos.cpp(56): note: The event handler is one of:
linklogos.cpp(56): note: could be 'void CEventReceiver::OnLogosPanelChanged(IDispatch *,IDispatch* )'
linklogos.cpp(56): note: There are no events:
logoscom.tli(113): note:     'HRESULT Logos4Lib::ILogosApplicationEvents::PanelChanged(IDispatch *,IDispatch* )':is not an event

This error relates to the line:

    __unhook(&Logos4Lib::ILogosApplicationEvents::PanelChanged, pEventSource,&CEventReceiver::OnLogosPanelChanged);


linklogos.cpp(75): error C2259: 'Logos4Lib::ILogosApplicationEvents': cannot instantiate abstract class
linklogos.cpp(75): note: due to following members:
linklogos.cpp(75): note: 'HRESULT IUnknown::QueryInterface(const IID &,void **)':is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\unknwnbase.h(113): note: see declaration of 'IUnknown::QueryInterface'
linklogos.cpp(75): note: 'ULONG IUnknown::AddRef(void)': is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\unknwnbase.h(117): note: see declaration of 'IUnknown::AddRef'
linklogos.cpp(75): note: 'ULONG IUnknown::Release(void)': is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\unknwnbase.h(119): note: see declaration of 'IUnknown::Release'
linklogos.cpp(75): note: 'HRESULT IDispatch::GetTypeInfoCount(UINT *)': is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\oaidl.h(2204): note: see declaration of 'IDispatch::GetTypeInfoCount'
linklogos.cpp(75): note: 'HRESULT IDispatch::GetTypeInfo(UINT,LCID,ITypeInfo **)':is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\oaidl.h(2207): note: see declaration of 'IDispatch::GetTypeInfo'
linklogos.cpp(75): note: 'HRESULT IDispatch::GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID* )':is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\oaidl.h(2212): note: see declaration of 'IDispatch::GetIDsOfNames'
linklogos.cpp(75): note: 'HRESULT IDispatch::Invoke(DISPID,const IID &,LCID,WORD,DISPPARAMS *,VARIANT* ,EXCEPINFO *,UINT* )':is abstract
c:\program files (x86)\windows kits\10\include\10.0.16299.0\um\oaidl.h(2219): note: see declaration of 'IDispatch::Invoke'

This error relates to the line:

    Logos4Lib::ILogosApplicationEvents eventSource;


The first error message is perhaps the most troubling...  Any ideas?

All I want to do is browse for a bmp and display it scaled in a dialog based app....how?

$
0
0

Apparently there is no possible way to manually load the bitmap from a file and scale it into the static control.

All the suggestions involving createCompatibleDC(...) just don't work.

And I have tried making my static control owner draw, creates a custom static class that responds to WM_DRAWITEM but then I get a ASSERT failure error in CStatic:: OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

So apparently my DDX_Control(pDX, IDC_STATIC_BMP, m_staticBMP/*CBitmapCtrl*/) does not work....why?


The image I select may be larger or smaller than the dimensions of the staic control.

In visual studio 2008 how to set style SS_WHITERECT to static control from resource editor?

$
0
0

Hi,

In visual studio 2008 how to set style SS_WHITERECT to static control from resource editor?

Viewing all 15302 articles
Browse latest View live