FAQ del grupo de noticias microsoft.public.es.vc++

ATENCION: Esta faq ya no se mantiene. No se añaden nuevas entradas.
La nueva ubicación de esta faq es mi
blog dentro de Geeks.ms, selecciona la sección dedicada a C++
Geeks.ms es una comunidad online donde podrás encontrar los blogs y foros de un buen puñado de MVPs y MCTs.

Esta faq es mantenida por Rodrigo Corral González [MicrosoftMost Valuable Professional]

Haz click para ir al sitio de MVP Haz click para ir al sitio de MCAD

Esta faq se puede distribuir y modificar libremente, si la modificas seria buena idea que compartieses esas modificaciones.
Si tienes alguna sugerencia no dudes en hacerla a través del grupo de news o usando el correo que puedes encontrar en el pie de pagina

Nuevo proyecto de formación con cursos creados en exclusiva por MVPs!!! Hechale un vistazo a la web de Campus MVP, hay gran variedad de cursos online impartidos por los profesionales mejor valorados por Microsoft!!! Además estos cursos pueden salirte gratis

Visita www.campusmvp.com el proyecto de formación online de los profesionales mejor valorado por Microsoft

 

Contenido

¿Como puedo utilizar una DLL de Visual Basic desde VC++?
¿Como crear una DLL en VC++ que se pueda usar desde VBScript y Visual Basic?
¿Como puedo obtener el directorio en el que se encuentra el ejecutable de la aplicación?
¿Como detectar si una aplicación ya esta corriendo?
¿Como acceder a bases de datos desde VC++?
¿Cuales son las diferencias entre MFC/WTL/STL/ATL?
¿Como hago que una ventana sea siempre visible?
¿Cómo puedo hacer que la ejecución de una tarea en mi progama no me bloquee la ventana?
¿Como programo con hilos?
¿Es Visual C++ 'visual'? ¿Es una herramienta RAD?
¿Como obtengo el path de capetas del sistema (por ejemplo System, Archivos de Programa etc...)?
¿Como mostrar imagenes en una ventana?
¿Que son las DLL de extensión?
¿Que hago si no quiero depender de una DLL pero quiero hacer un modulo con funciones reutilizables?
El combo no se despliega ¿qué ocurre?
¿Como minimizo las dll de las que depende mi ejecutable?
¿Cómo puedo acceder al puerto serie/paralelo?
¿Cómo hago que mi aplicación soporte multiples idiomas?
¿Cómo se si mi proceso fue lanzado con privilegios de administrador?

¿Como puedo utilizar una DLL de Visual Basic desde VC++?

Las DLL construidas con VB exportan objetos COM.

La manera más simple de usar objetos COM desde VC++ es usando la directiva #import y los smart pointers de COM que genera esta directiva.

El mecanismo sería algo como:

#import "tuDLL.DLL"
using namespace tuDLL
...
//Crear un objeto
_TuClaseVBPtr tuClase(__uuidof(TuClaseVB));
tuClase->MetodoDeTuClaseVB();

¿Como crear una DLL en VC++ que se pueda usar desde VBScript y Visual Basic?

Basicamente tienes que crear una DLL COM. y tener en cuenta que las interfaces de los objetos que exporten deben de ser duales y debes marcarlas como oleautomation.

La manera más simple de crear objetos COM en VC++ es usar ATL.

Este link te sera de utilidad:
Building COM Components That Take Full Advantage of Visual Basic and Scripting

Eso si, si no estas familiarizado con el desarrollo COM en VC++, bien mediante MFC o ATL la tarea no es simple.

¿Como puedo obtener el directorio en el que se encuentra el ejecutable de la aplicación?

TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL, szPath, MAX_PATH);
//Quitamos el nombre del ejecutable
//Tambien puedes usar PathRemoveFileSpec o splitpath si no estamos usando MFC o ATL
CString strAppPath(szPath);
strAppPath = strAppPath.Left(strAppPath.ReverseFind('\\'));

¿Como detectar si una aplicación ya esta corriendo?

La forma más habitual de hacerlo es creando un objeto mutex global (con nombre) y verificar su estado. El siguiente fragmente de código Win32 muestra cómo hacerlo:

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    HACCEL hAccelTable;
    // Codigo previo... 
    // Controlar instancias previas
    HANDLE hMtx = CreateMutex( NULL, FALSE, "{FA531CC1-0497-11d3-A180-001052276C3E}" );
    if( GetLastError() == ERROR_ALREADY_EXISTS ) return FALSE;
    // Resto de código...
    return msg.wParam;
}

Un mutex con nombre es un objeto Kernel que puede ser verificado desde cualquier proceso. La primera aplicación lo creará sin problema, pero al intentar crearlo desde un segundo proceso, retornará ERROR_ALREADY_EXISTS. Retornando FALSE desde el WinMain provocamos la salida del programa.

Otro enfoque que tambien que se utiliza en ocasiones es buscar la ventana principal de tu aplicación con la función FindWindow. La ventaja es que una vez localizada la ventana puedes traer esta a primer plano, en lugar de simplemente informar al usuario de que no puede arracar otra instancia de la aplicación.

¿Como acceder a bases de datos desde VC++?

La mejor opción es usar ADO mediante la directiva #import. Lee el siguiente articulo para saber como hacerlo:

Artículo de Microsoft Knowledge Base - 169496 INFO: Using ActiveX Data Objects (ADO) via #import in VC++

¿Cuales son las diferencias entre MFC/WTL/STRL/ATL?

MFC (Microsoft Fundation Classes): Libreria basada en jeraquia de clases, basicamente encapsula el API de windows en una forma orientada a objetos.

ATL (Active Template Library): Es una libreria basada en templates, que se creo para relizar controles y librerias ActiveX (COM) de bajo peso. El motivo fue el excesivo peso que MFC añadia a los ActiveX que perjidicaba su distribución desde internet.

WTL (Windows Template Library): Es una libreria en cierto modo similar a MFC solo que basada en templates y menos extensa, por ejemplo carece de clases para sockets, o bases de datos. Esta muy relacionada con ATL, a la que añade la posibilidad de trabajar con ventanas.

STL (Standar Template Libary): Es la libreria estandar de C++, se puede encontrar en practicamente cualquier compilador de C++. Contiene clases para multiples propositos como porejemplo trabajar con cadenas, algoritmos, clases de colecciones (listas,mapas...), los streams de C++ y muchas consas mas. Puedes mirar:
http://www.sgi.com/tech/stl/
http://www.stlport.org/

¿Como hacer una ventana siempre visible?

Hay que usar el api SetWindowPos de la siguente manera:

Para hacer la ventan siempre visible

SetWindowPos(hwnd, HWND_TOPMOST, 0,  0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE |WP_NOSIZE);

Para devolverle el comportamiento normal

SetWindowPos(hwnd, HWND_NOTOPMOST, 0,  0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE| WP_NOSIZE);

Si estas trabajando en MFC la función SetWindowPos sera miembro de la clase
que representa tu ventana.

¿Cómo puedo hacer que la ejecución de una tarea en mi progama no me bloquee la ventana?

Para evitarlo lo que tienes que hacer es crear un hilo de ejecución para
realizar la tarea que deja bloqueada la ventana.

Si no quieres complicarte con hilos y la tarea que realizas es de tipo iterativo puedes poner en cada paso de bucle llamadas a la siguiente función, que permite que se procesen los mensajes de ventana de manera que esta no se quede muerta, de todos modos te recomiento que uses los hilos, ya que este método consume mucha CPU.

void CApplication::DoEvents()
{
 MSG msg;
    while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
    {
        if ( !PumpMessage( ) )
        {
            ::PostQuitMessage(0);
            break;
        }
    }
    // let MFC do its idle processing
    for (long lIdle = 0; OnIdle(lIdle); lIdle++ ){;}
}

¿Como programo con hilos?

Basicamente, lo que necesitas conocer a es:
    1) Como levantar hilos
    2) Como sincronizar el trabajo realizado por hilos (conocer los objetos de sincronización)

Esto depende de la plataforma en la que estes programando (C 'puro', C++, UNIX, Win32, MFC) ya que cada plataforma expone diferentes objetos y funciones para realizar estas tareas. Existen librerias que te abstraen de estas diferencias (p.e.: Boost.Threads http://www.boost.org/libs/thread/doc/index.html)

Otro tema es el diseño de programas multihilo eficientes y sin problemas, que es un arte más que una ciencia y como tal depende mucho de la experiencia.

Si quieres centrarte en plataforma Windows, busca Multitherading en la MSDN, tienes información para dar y colgar.

Articulos interesantes en la MSDN son:

Multithreading for Rookies
Synchronization on the Fly
Using Multithreading and C++ to Generate Live Objects

Por ultimo dos libros, que te comento por que los he leido, no por que sean
los mejores que eso no lo se.

Este centrado en Windows:
Multithreading Applications in Win32 : The Complete Guide to Threads
by Jim Beveridge (Author), Robert Wiener (Author)

Y este que habla de las posiblidades en diferentes sistemas operativos (ojo,
no sirve para aprender)
Multithreading Programming Techniques (J. Ranade Workstation Series)
by Shashi Prasad, Shshi Prasad, Shashi Prashad

¿Es Visual C++ 'visual'? ¿Es una herramienta RAD?

Aunque Visual C++ si que es 'visual' en el sentido que permite realizar gran parte de las tareas mediante asistentes, no es un entorno RAD al estilo de Visual Basic o FoxPro.
 
Si bien la manera de trabajar es diferente, tambien sigue el paradigma de arrastrar y soltar controles, lo que no es visual es el establecer todas las opciones de los controles y estos no tiene tantas propiedades y métodos como en las hermientas RAD. Para darles un comportamiento más rico tienes que usar código.
 
La potencia de Visual C++ esta principalmente en que tu tienes el control y eso tiene ventajas he inconvenientes. Tambien te comento que en mi opinión para apliacaciones basadas en formularios las hermientas RAD son más productivas, pero VC++ es superior si se trata de construir programas que exijan mucho procesamiento, graficos muy avanzados, aplicaciones basadas en documentos o con una interfaz no basada en formularios y en general componentes para ser usados desde otros lenguajes, y por supesto toda la programación a 'bajo nivel' (drivers, extensiones de shell,...).

¿Como obtengo el path de capetas del sistema (por ejemplo System, Archivos de Programa etc...)?

Debes usar la función SHGetFolderPath, si quieres añadir un subdirectorio al valor devuelto (p.e.: C:\Archivos de programa\Tu applicacion) lo puedes hacer directamente con la función SHGetFolderPathAndSubDir. Estas funciones tienen como requisito Windows 95 con Internet Explorer 5.0, Windows 98 con Internet Explorer 5.0, Windows 98 Second Edition (SE), Windows NT 4.0 con Internet Explorer 5.0, Windows NT 4.0 con Service Pack 4 (SP4).

Tambien puedes utilizar las siguientes funciones:

GetSystemDirectory(), para obtener el directorio de sistema.
GetWindowsDirectory(), para obtener el directorio de windows.
GetTempPath(), para obtener el directorio temporal.

¿Como mostrar imagenes en una ventana?

Conozco 2 maneras de realizar esto:

1) Utilizar la clase CPiture (que encapsula la interfaz IPicture), escrita
por Paul Dilascia,  que permite usar JPG, GIFF y BITMAP y sobre la que
puedes encontrar información en los siguientes vinculos:

Displaying a JPG in your MFC Application

2) Utilizar el nuevo API GDI+ que permite trabajar con BMP, JPEG, PNG, GIF y
TIFF y estas disponible como un runtime de aproximadamente 1 Mb de tamaño.
Esta libreria es propocionada sin ningún royalti como distribuible por
Microsoft. Mira el siguiente vinculo:

GDI+

Para cargar una imagen JPEG y mostarla en una ventana conocido el handle de
su DC en puedes usar la siguiente función:

 void ShowJPG(HANDLE hDC)
 {
     Graphics graphics(hDC);
     Image image("photo.jpg");
     graphics.DrawImage(&image, 10, 10);
 }

¿Que son las DLL de extensión?

Las DLL de extensión de MFC tipicamente exponen classes derivadas de clases standard existente en MFC. Solo se pueden linkar de manera dinamica con lavDLL de runtima de MFC y solo aplicacines u otras DLL linkadas de manera dinamica con la DLL de runtime de MFC pueden usar DLL de extensión. El pricipal proposito de las DLL de extensión es derivar tu propias clases de clases de MFC y permitir que otras aplicaciones usen estas clases extendidas a través de la DLL de extensión.

Las DLL de extensión tambien son utiles cuando en la interfaz de la DLL se exponen objetos de MFC (p.e. una función que toma como parametros un CEdit), aunque en mi opinión esto es un mal diseño en la mayoria de los casos.

Excepto en los casos expuesto arriba, es preferible usar DLL normales.

¿Que hago si no quiero depender de una DLL pero quiero hacer un modulo con funciones reutilizables?

Crea un libreria estática (.LIB) en lugar de una libreria dinámica. Tambien puedes convertir tu librerias dinamicas en estaticas sin tener que cambiar el código.

El combo no se despliega ¿qué ocurre?

Cuando pones un control combo sobre un dialogo en el editor de dialogos, tienes que dimensionar el tamaño del desplegable, que por defecto es muy pequeño. Para ello selecciona el control en el editor, pulsa sobre el icono
de depliegue del combo y arrastra los cuadraditos de dimensionar.

Tambien lo puedes hacer por código:

ComboBox.SetWindowPos(NULL,0,0,100,200,SWP_NOMOVE | SWP_NOZORDER);

¿Como minimizo las dll de las que depende mi ejecutable?

La solución consiste en linkar estáticamente el runtima de MFC (menú Project\Settings\Microsoft foundation class) y el runtime de C/C++ (Project\Settings\C/C++\Category\Code Generation\Use Runtime Library)
Esto no evitará las dependencias de DLLs o controles ActiveX (OCX) que deberás distribuir con tu
ejecutable.

Si usas librerias dinámicas (DLL) propias conviertelas en librerias estaticas (LIB), lee la FAQ #17 para saber como.

¿Cómo puedo acceder al puerto serie/paralelo?

Tienes que usar las funciones del API de Win32 habituales para trabajar con ficheros, OpenFile, ReadFile, WriteFile, expecificando como nombre de fichero el nombre del puerto que quieres usar "LPTx" o "COMx".

Este articulo sobre el tema es muy intersante Serial Communication in Windows By Ashish Dhar

¿Cómo hago que mi aplicación soporte multiples idiomas?

Un enfoque que se utiliza bastante es el de tener una dll de recursos para cada idioma que se desea soportar. Esta dll se carga dinamicamente con LoadLibray (o AfxLoadLibray en MFC) y se establece como origen de los recursos. Para saber como crear esta dll lee Creating a Resource-Only DLL en la MSDN.

Tipicamente harás esto en InitInstace:

BOOL CMyApp::InitInstance()
{
  //Default Appwizard code.
  HINSTANCE hRes = NULL;
  hRes= LoadLibrary("ResourceD.dll");
  if(hRes)
    AfxSetResourceHandle(hRes);
  //Rest of wizard code
  return CWinApp::InitInstance();
}

En ATL/WTL para establecer la dll cargada como origen de los recursos se utiliza la función
CAtlBaseModule::SetResourceInstance.

Usando el API se utiliza LoadResource, LoadString etc... para cargar los recursos, pasando como primer parametro el handle de la libreria de recursosque previamente hemos cargado con LoadLibrary.

¿Cómo se si mi proceso fue lanzado con privilegios de administrador?

Aqui va una función que permite averiguarlo:

//Comprueba que el usuario que inicio el proceso sea administrador
bool UserIsAdmin(void)
{
    bool bSuccess = false;

    //Obetenemos el token del proceso
    HANDLE hToken = NULL;
    if ( !OpenProcessToken ( GetCurrentProcess ( ), TOKEN_QUERY, &hToken ) )
        return false;

    //Obtenemos el tamaño necesarios para la información del grupos
    //asociados al token del proceso
    DWORD dwSize = 0;
    bSuccess = GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize) != 0;
    if( !bSuccess && ERROR_INSUFFICIENT_BUFFER != ::GetLastError() )
        return false;

    //Dimensionamos el buffer para los tokens de los grupos
    PTOKEN_GROUPS pGroups = (PTOKEN_GROUPS) new BYTE[dwSize];

    //Obtenemos la inforamción sobre los grupos
    bSuccess = GetTokenInformation ( hToken, TokenGroups,
                                                          (LPVOID)pGroups, dwSize, 
                                                          &dwSize ) != 0;

    //Cerramos el token del proceso
    CloseHandle ( hToken );

    if ( !bSuccess ) return false;

    //Obtenemos el sid de aministrador
    SID_IDENTIFIER_AUTHORITY siaNtAuth = SECURITY_NT_AUTHORITY;
    PSID pAdminSid = NULL;
    if ( !AllocateAndInitializeSid ( &siaNtAuth, 2,
                                                  SECURITY_BUILTIN_DOMAIN_RID,
                                                  DOMAIN_ALIAS_RID_ADMINS,
                                                  0,0,0,0,0,0, &pAdminSid ) )
    return false;

    bSuccess = false;

    //Comprobamos si el token de administrador esta entre los del
    //proceso, si es asi el proceso tiene privilegios de administrador
    for ( DWORD i = 0; (i < pGroups->GroupCount) && !bSuccess; i++ )
   {
       if ( EqualSid ( pAdminSid, pGroups->Groups[i].Sid ) )
             bSuccess = true;
   }

    //Liberamos el sid
    FreeSid ( pAdminSid );
    //Liberamos la memoria
   delete[] pGroups;

   return bSuccess;

}

Proximas entregas....

¿Como creo una DLL?

¿Como uso una DLL?

¿Como convertir una libreria dinámica (DLL) en estatica (LIB)?